timetrap 1.4.1 → 1.5.0

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/.gitignore CHANGED
@@ -1 +1,2 @@
1
1
  tags
2
+ pkg
data/README.md CHANGED
@@ -135,7 +135,7 @@ Commands
135
135
  start or end times. Defaults to the current time although an ``--id`` flag can
136
136
  be passed with the entry's id (see display.)
137
137
 
138
- usage: ``t edit [--id ID] [--start TIME] [--end TIME] [NOTES]``
138
+ usage: ``t edit [--id ID] [--start TIME] [--end TIME] [--append] [NOTES]``
139
139
 
140
140
  **format**
141
141
  Deprecated
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
2
  :major: 1
3
- :minor: 4
4
- :patch: 1
3
+ :minor: 5
4
+ :patch: 0
data/lib/timetrap.rb CHANGED
@@ -57,7 +57,6 @@ module Timetrap
57
57
  Entry.create(:sheet => Timetrap.current_sheet, :note => note, :start => time).save
58
58
  rescue => e
59
59
  CLI.say e.message
60
- CLI.say e.backtrace.join("\n")
61
60
  end
62
61
 
63
62
  def switch sheet
data/lib/timetrap/cli.rb CHANGED
@@ -28,10 +28,13 @@ where COMMAND is one of:
28
28
  -f, --format <format> The output format. Currently supports ical, csv, and
29
29
  text (default).
30
30
  * edit - alter an entry's note, start, or end time. Defaults to the active entry
31
- usage: t edit [--id ID] [--start TIME] [--end TIME] [NOTES]
31
+ usage: t edit [--id ID] [--start TIME] [--end TIME] [--append] [NOTES]
32
32
  -i, --id <id:i> Alter entry with id <id> instead of the running entry
33
33
  -s, --start <time:qs> Change the start time to <time>
34
34
  -e, --end <time:qs> Change the end time to <time>
35
+ -z, --append Append to the current note instead of replacing it
36
+ the delimiter between appended notes is
37
+ configurable (see configure)
35
38
  * format - deprecated: alias for display
36
39
  * in - start the timer for the current timesheet
37
40
  usage: t in [--at TIME] [NOTES]
@@ -67,6 +70,9 @@ where COMMAND is one of:
67
70
 
68
71
  def invoke
69
72
  args['-h'] ? say(USAGE) : invoke_command_if_valid
73
+ rescue => e
74
+ say e.message
75
+ exit 1
70
76
  end
71
77
 
72
78
  def commands
@@ -116,7 +122,13 @@ where COMMAND is one of:
116
122
  say "can't find entry" && return unless entry
117
123
  entry.update :start => args['-s'] if args['-s'] =~ /.+/
118
124
  entry.update :end => args['-e'] if args['-e'] =~ /.+/
119
- entry.update :note => unused_args if unused_args =~ /.+/
125
+ if unused_args =~ /.+/
126
+ note = unused_args
127
+ if args['-z']
128
+ note = [entry.note, note].join(Config['append_notes_delimiter'])
129
+ end
130
+ entry.update :note => note
131
+ end
120
132
  end
121
133
 
122
134
  def backend
@@ -14,7 +14,9 @@ module Timetrap
14
14
  # Path to the sqlite db
15
15
  'database_file' => "#{ENV['HOME']}/.timetrap.db",
16
16
  # Unit of time for rounding (-r) in seconds
17
- 'round_in_seconds' => 900
17
+ 'round_in_seconds' => 900,
18
+ # delimiter used when appending notes with `t edit --append`
19
+ 'append_notes_delimiter' => ' '
18
20
  }
19
21
  end
20
22
 
@@ -28,10 +30,13 @@ module Timetrap
28
30
  end
29
31
 
30
32
  def configure!
31
- unless File.exist?(PATH)
32
- File.open(PATH, 'w') do |fh|
33
- fh.puts(defaults.to_yaml)
34
- end
33
+ configs = if File.exist?(PATH)
34
+ defaults.merge(YAML.load_file(PATH))
35
+ else
36
+ defaults
37
+ end
38
+ File.open(PATH, 'w') do |fh|
39
+ fh.puts(configs.to_yaml)
35
40
  end
36
41
  end
37
42
  end
@@ -14,11 +14,11 @@ module Timetrap
14
14
  end
15
15
 
16
16
  def start= time
17
- self[:start]= Chronic.parse(time.to_s) || time
17
+ self[:start]= process_time(time)
18
18
  end
19
19
 
20
20
  def end= time
21
- self[:end]= Chronic.parse(time.to_s) || time
21
+ self[:end]= process_time(time)
22
22
  end
23
23
 
24
24
  def start
@@ -56,6 +56,36 @@ module Timetrap
56
56
  map{|e|e.sheet}.uniq.sort
57
57
  end
58
58
 
59
+ private
60
+ def process_time(time)
61
+ case time
62
+ when Time
63
+ time
64
+ when String
65
+ if parsed = Chronic.parse(time)
66
+ parsed
67
+ elsif safe_for_time_parse?(time) and parsed = Time.parse(time)
68
+ parsed
69
+ else
70
+ raise ArgumentError, "Could not parse #{time.inspect}, entry not updated"
71
+ end
72
+ end
73
+ end
74
+
75
+ # Time.parse is optimistic and will parse things like '=18' into midnight
76
+ # on 18th of this month.
77
+ # It will also turn 'total garbage' into Time.now
78
+ # Here we do some sanity checks on the string to protect it from common
79
+ # cli formatting issues, and allow reasonable warning to be passed back to
80
+ # the user.
81
+ def safe_for_time_parse?(string)
82
+ # misformatted cli option
83
+ !string.include?('=') and
84
+ # a date time string needs a number in it
85
+ string =~ /\d/
86
+ end
87
+
88
+
59
89
  # do a quick pseudo migration. This should only get executed on the first run
60
90
  set_schema do
61
91
  primary_key :id
@@ -69,7 +69,7 @@ describe Timetrap do
69
69
  end
70
70
  end
71
71
 
72
- it "should descirve config file" do
72
+ it "should describe config file" do
73
73
  FakeFS do
74
74
  invoke "configure"
75
75
  $stdout.string.should == "Config file is at \"#{ENV['HOME']}/.timetrap.yml\"\n"
@@ -88,6 +88,15 @@ describe Timetrap do
88
88
  Timetrap.active_entry.note.should == 'new description'
89
89
  end
90
90
 
91
+ it "should allow appending to the description of the active period" do
92
+ Timetrap::Config.stub(:[]).with('append_notes_delimiter').and_return('//')
93
+ Timetrap.active_entry.note.should == 'running entry'
94
+ invoke 'edit --append new'
95
+ Timetrap.active_entry.note.should == 'running entry//new'
96
+ invoke 'edit -z more'
97
+ Timetrap.active_entry.note.should == 'running entry//new//more'
98
+ end
99
+
91
100
  it "should edit the start time of the active period" do
92
101
  invoke 'edit --start "yesterday 10am"'
93
102
  Timetrap.active_entry.start.should == Chronic.parse("yesterday 10am")
@@ -329,6 +338,22 @@ END:VCALENDAR
329
338
  invoke 'in work --at "10am 2008-10-03"'
330
339
  Timetrap::Entry.order_by(:id).last.start.should == Time.parse('2008-10-03 10:00')
331
340
  end
341
+
342
+ it "should fail with a warning for misformatted cli options it can't parse" do
343
+ now = Time.now
344
+ Time.stub!(:now).and_return now
345
+ invoke 'in work --at="18 minutes ago"'
346
+ Timetrap::Entry.order_by(:id).last.should be_nil
347
+ $stdout.string.should =~ /\w+/
348
+ end
349
+
350
+ it "should fail with a time argurment of total garbage" do
351
+ now = Time.now
352
+ Time.stub!(:now).and_return now
353
+ invoke 'in work --at "total garbage"'
354
+ Timetrap::Entry.order_by(:id).last.should be_nil
355
+ $stdout.string.should =~ /\w+/
356
+ end
332
357
  end
333
358
 
334
359
  describe "kill" do
data/timetrap.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{timetrap}
8
- s.version = "1.4.1"
8
+ s.version = "1.5.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Sam Goldstein"]
12
- s.date = %q{2010-10-28}
12
+ s.date = %q{2010-10-30}
13
13
  s.default_executable = %q{t}
14
14
  s.description = %q{Command line time tracker}
15
15
  s.email = %q{sgrock@gmail.com}
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: timetrap
3
3
  version: !ruby/object:Gem::Version
4
- hash: 5
4
+ hash: 3
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
- - 4
9
- - 1
10
- version: 1.4.1
8
+ - 5
9
+ - 0
10
+ version: 1.5.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sam Goldstein
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-10-28 00:00:00 -07:00
18
+ date: 2010-10-30 00:00:00 -07:00
19
19
  default_executable: t
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency