tempo-cli 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +2 -0
- data/Rakefile +2 -1
- data/bin/tempo +11 -1
- data/features/end.feature +1 -4
- data/features/start.feature +23 -0
- data/features/update.feature +27 -0
- data/lib/tempo/controllers/start_controller.rb +18 -1
- data/lib/tempo/controllers/update_controller.rb +25 -1
- data/lib/tempo/models/log.rb +7 -0
- data/lib/tempo/models/time_record.rb +7 -1
- data/lib/tempo/version.rb +1 -1
- data/lib/tempo/views/base.rb +8 -0
- data/lib/time_utilities.rb +5 -0
- data/test/lib/tempo/exceptions_test.rb +5 -5
- data/test/lib/tempo/models/log_test.rb +5 -1
- data/test/lib/tempo/models/time_record_test.rb +17 -4
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 020b9afac83811fcaf37f57bf03ba5553677134f
|
4
|
+
data.tar.gz: 90c5735ba9f705f1a8428a7c99cdcb0dcb74cf3f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1acba9a88b45b4e2f4ba85a301da99e4b880c4681b46fcb0bf2c552f074c865bc66abeab6919c6687f839d4c00157522abff3fa531b466255a86152f781fcca
|
7
|
+
data.tar.gz: e5820580c779d3b956ac57ad7c9d799da3951c1cd9b58682aaecd024cdc0208a708f4b758515fce905a5f55176f537adea024e05658b0f45c336fc7512a14824
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -150,6 +150,7 @@ New projects are added as root projects by default. Use arrange to arrange exist
|
|
150
150
|
##### command options
|
151
151
|
--at=time
|
152
152
|
--end=time
|
153
|
+
--restart
|
153
154
|
|
154
155
|
Starts a new time entry, and closes out any running time entries.
|
155
156
|
|
@@ -197,6 +198,7 @@ New projects are added as root projects by default. Use arrange to arrange exist
|
|
197
198
|
--id=number - Select by Id
|
198
199
|
--on=date - Select On Date
|
199
200
|
--project - Update to the active project
|
201
|
+
--running - Set the last project back to running (reopen the end-time)
|
200
202
|
--start=time - Update the Start Time
|
201
203
|
|
202
204
|
update the project, start time, or end time for a time entry.
|
data/Rakefile
CHANGED
@@ -4,6 +4,7 @@ require 'rubygems/package_task'
|
|
4
4
|
require 'rdoc/task'
|
5
5
|
require 'cucumber'
|
6
6
|
require 'cucumber/rake/task'
|
7
|
+
require "fileutils"
|
7
8
|
|
8
9
|
Rake::RDocTask.new do |rd|
|
9
10
|
rd.rdoc_files.include("lib/**/*.rb","bin/**/*")
|
@@ -62,4 +63,4 @@ task :clean => [:tests_setup, :tests_teardown]
|
|
62
63
|
|
63
64
|
task :default => [:tests_setup, :run_tests, :features, :tests_teardown]
|
64
65
|
|
65
|
-
task 'features:focus' => [:tests_setup, :run_tests, 'cucumber:focus'
|
66
|
+
task 'features:focus' => [:tests_setup, :run_tests, 'cucumber:focus']
|
data/bin/tempo
CHANGED
@@ -261,6 +261,10 @@ To start a time entry at a time other than the current, pass it in as an argumen
|
|
261
261
|
to the --at flag. This will accept a number of human readable formats, multiple
|
262
262
|
word time formats should be enclosed in quotes.
|
263
263
|
|
264
|
+
Use the --resume flag to start a new time entry with the last used project and description.
|
265
|
+
|
266
|
+
To reopen the last time entry (change the end time back to 'running') see `tempo update --running`
|
267
|
+
|
264
268
|
examples:
|
265
269
|
|
266
270
|
# start a new time record at the current time with no description
|
@@ -275,6 +279,9 @@ $ tempo start learning how to do the Hustle --at 'yesterday at 8:00 in the eveni
|
|
275
279
|
arg_name 'description'
|
276
280
|
command [:start, :s] do |c|
|
277
281
|
|
282
|
+
c.desc 'start an entry using the last description and project'
|
283
|
+
c.switch [:r, :resume], negatable: false
|
284
|
+
|
278
285
|
c.desc 'end the entry at a given time'
|
279
286
|
c.arg_name 'time'
|
280
287
|
c.flag [:e, :end]
|
@@ -432,6 +439,9 @@ command [:update, :u] do |c|
|
|
432
439
|
c.arg_name 'time'
|
433
440
|
c.flag [:s, :start]
|
434
441
|
|
442
|
+
c.desc 'Change the last time entry back to actively running (ignores all other options)'
|
443
|
+
c.switch [:r, :running], negatable: false
|
444
|
+
|
435
445
|
c.desc 'Update the End Time'
|
436
446
|
c.arg_name 'time'
|
437
447
|
c.flag [:e, :end]
|
@@ -487,7 +497,7 @@ on_error do |exception|
|
|
487
497
|
# return false to skip default error handling
|
488
498
|
|
489
499
|
# remove before distribution:
|
490
|
-
|
500
|
+
puts exception.backtrace
|
491
501
|
|
492
502
|
true
|
493
503
|
end
|
data/features/end.feature
CHANGED
@@ -40,6 +40,7 @@ Feature: End Command ends the current time record
|
|
40
40
|
And I run `tempo end --at "1-5-2014 15:00"`
|
41
41
|
Then the stdout should contain "time record ended"
|
42
42
|
And the output should match /7:00 - 15:00/
|
43
|
+
|
43
44
|
@pending
|
44
45
|
Scenario: Attempting to end after the beginning time
|
45
46
|
Given an existing project file
|
@@ -59,7 +60,3 @@ Feature: End Command ends the current time record
|
|
59
60
|
And the time record 20140101 should contain ":end_time: 2014-01-01 23:59" at line 5
|
60
61
|
And the time record 20140102 should contain ":end_time: 2014-01-01 23:59" at line 5
|
61
62
|
And the time record 20140103 should contain ":end_time: 2014-01-01 10:00" at line 5
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
data/features/start.feature
CHANGED
@@ -70,6 +70,29 @@ Feature: Start Command starts a new time record
|
|
70
70
|
Then the stdout should contain "time record started"
|
71
71
|
And the time record 20140101 should contain ":end_time: 2014-01-01 10:00" at line 5
|
72
72
|
|
73
|
+
Scenario: Resuming the last time record
|
74
|
+
Given an existing project file
|
75
|
+
When I run `tempo start --at "1-1-2014 10:00" tweezing the cactus`
|
76
|
+
And I run `tempo end --at "1-1-2014 12:00"`
|
77
|
+
And I successfully run `tempo start --resume --at "1-1-2014 13:00"`
|
78
|
+
Then the stdout should contain "time record started"
|
79
|
+
And the time record 20140101 should contain ":description: tweezing the cactus" at line 11
|
80
|
+
|
81
|
+
Scenario: Resuming the last time record with a different project checked out ignores current project
|
82
|
+
Given an existing project file
|
83
|
+
When I run `tempo start --at "1-1-2014 10:00" tweezing the cactus`
|
84
|
+
And I run `tempo end --at "1-1-2014 12:00"`
|
85
|
+
And I run `tempo checkout basement mushrooms`
|
86
|
+
And I successfully run `tempo start --resume --at "1-1-2014 13:00"`
|
87
|
+
Then the stdout should contain "time record started"
|
88
|
+
And the time record 20140101 should contain ":project_title: horticulture" at line 10
|
89
|
+
|
90
|
+
Scenario: Attempting to resume the last project when one is running
|
91
|
+
Given an existing project file
|
92
|
+
When I run `tempo start --at "1-1-2014 10:00"`
|
93
|
+
And I run `tempo start --resume`
|
94
|
+
Then the stderr should contain "error: cannot resume last time record when it is still running"
|
95
|
+
|
73
96
|
Scenario: Adding an earlier day time record should immediately close out
|
74
97
|
Given an existing project file
|
75
98
|
When I run `tempo start --at "1-5-2014 7:00"`
|
data/features/update.feature
CHANGED
@@ -48,6 +48,14 @@ Feature: Update Command manages edits to the time records
|
|
48
48
|
Then the stdout should contain "time record updated:\n13:32 - 16:35 [3:03] nano aquarium: trimming the coral"
|
49
49
|
And the time record 20140101 should contain ":end_time: 2014-01-01 16:35:00" at line 37
|
50
50
|
|
51
|
+
Scenario: Restarting the last time record
|
52
|
+
Given an existing project file
|
53
|
+
When I run `tempo start --at "1-5-2015 7:00"`
|
54
|
+
And I run `tempo end --at "1-5-2015 15:00"`
|
55
|
+
And I run `tempo update --running`
|
56
|
+
Then the stdout should contain "time record updated"
|
57
|
+
And the time record 20150105 should contain ":end_time: :running" at line 5
|
58
|
+
|
51
59
|
Scenario: Updating to the project for the last time record
|
52
60
|
Given an existing project file
|
53
61
|
And an existing time record file
|
@@ -73,3 +81,22 @@ Feature: Update Command manages edits to the time records
|
|
73
81
|
Then the stdout should contain "time record updated:\n07:00 - 08:35 [1:35] horticulture: raking leaves"
|
74
82
|
And the time record 20131201 should contain ":end_time: 2013-12-01 08:35:00" at line 5
|
75
83
|
|
84
|
+
Scenario: Updating the start time on an earlier day passing only time no date
|
85
|
+
Given an existing project file
|
86
|
+
And an existing time record file
|
87
|
+
When I run `tempo start --at "12/1/2013 7:00" --end "12/1/2013 8:00" raking leaves`
|
88
|
+
And I run `tempo start --at "12/1/2013 9:00" --end "12/1/2013 10:00" counting rosebuds`
|
89
|
+
When I successfully run `tempo update --on "12/1/2013" --id 1 --start "7:35"`
|
90
|
+
Then the stdout should contain "time record updated:\n07:35 - 08:00 [0:25] horticulture: raking leaves"
|
91
|
+
And the time record 20131201 should contain ":start_time: 2013-12-01 07:35:00" at line 4
|
92
|
+
|
93
|
+
Scenario: Updating the end time on an earlier day passing only time no date
|
94
|
+
Given an existing project file
|
95
|
+
And an existing time record file
|
96
|
+
When I run `tempo start --at "12/1/2013 7:00" --end "12/1/2013 8:00" raking leaves`
|
97
|
+
And I run `tempo start --at "12/1/2013 9:00" --end "12/1/2013 10:00" counting rosebuds`
|
98
|
+
When I successfully run `tempo update --on "12/1/2013" --id 1 --end "8:35"`
|
99
|
+
Then the stdout should contain "time record updated:\n07:00 - 08:35 [1:35] horticulture: raking leaves"
|
100
|
+
And the time record 20131201 should contain ":end_time: 2013-12-01 08:35:00" at line 5
|
101
|
+
|
102
|
+
|
@@ -30,7 +30,24 @@ module Tempo
|
|
30
30
|
end
|
31
31
|
|
32
32
|
@time_records.load_last_day options
|
33
|
-
|
33
|
+
|
34
|
+
if options[:resume]
|
35
|
+
last_record = @time_records.last_record
|
36
|
+
|
37
|
+
return Views.error("cannot resume last time record when it is still running") if last_record.running?
|
38
|
+
|
39
|
+
opts[:description] = last_record.description
|
40
|
+
|
41
|
+
# we use the last used project, but don't save it as current
|
42
|
+
# in case a different project has been checked out.
|
43
|
+
@projects.current = @projects.find_by_id(last_record.project)
|
44
|
+
|
45
|
+
record = @time_records.new(opts)
|
46
|
+
|
47
|
+
else
|
48
|
+
record = @time_records.new(opts)
|
49
|
+
end
|
50
|
+
|
34
51
|
@time_records.save_to_file options
|
35
52
|
|
36
53
|
Views.start_time_record_view record
|
@@ -8,12 +8,27 @@ module Tempo
|
|
8
8
|
|
9
9
|
class << self
|
10
10
|
|
11
|
+
def running(options, args)
|
12
|
+
@time_records.load_last_day options
|
13
|
+
|
14
|
+
if @time_records.last_record.running?
|
15
|
+
Views.message "Last time record is currently running"
|
16
|
+
else
|
17
|
+
@time_records.last_record.running!
|
18
|
+
@time_records.save_to_file options
|
19
|
+
Views.update_time_record_view @time_records.last_record
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
11
23
|
def parse(options, args)
|
12
24
|
|
13
25
|
reassemble_the args
|
14
26
|
|
15
27
|
return Views.project_assistance if Model::Project.index.empty?
|
16
28
|
|
29
|
+
# Reopen last record and ignore all other values if passed --running switch
|
30
|
+
return running(options, args) if options[:running]
|
31
|
+
|
17
32
|
# Load last day, or specific day if options includes an on-date
|
18
33
|
if options[:on]
|
19
34
|
day = Time.parse options[:on]
|
@@ -52,9 +67,13 @@ module Tempo
|
|
52
67
|
start_time = Time.parse options[:start]
|
53
68
|
return Views.no_match_error( "valid timeframe", options[:at], false ) if start_time.nil?
|
54
69
|
|
55
|
-
# TODO: add "today " to start time and try again if not valid
|
56
70
|
if record.valid_start_time? start_time
|
57
71
|
record.start_time = start_time
|
72
|
+
|
73
|
+
# try to update the time on the day, to handle updating with time params only
|
74
|
+
elsif record.valid_start_time? start_time.on_date(record.start_time)
|
75
|
+
record.start_time = start_time.on_date(record.start_time)
|
76
|
+
|
58
77
|
else
|
59
78
|
return Views::ViewRecords::Message.new "cannot change start time to #{start_time.strftime('%H:%M')}", category: :error
|
60
79
|
end
|
@@ -68,6 +87,11 @@ module Tempo
|
|
68
87
|
# TODO: add "today " to end time and try again if not valid
|
69
88
|
if record.valid_end_time? end_time
|
70
89
|
record.end_time = end_time
|
90
|
+
|
91
|
+
# try to update the time on the day, to handle updating with time params only
|
92
|
+
elsif record.valid_end_time? end_time.on_date(record.end_time)
|
93
|
+
record.end_time = end_time.on_date(record.end_time)
|
94
|
+
|
71
95
|
else
|
72
96
|
return Views::ViewRecords::Message.new "cannot change end time to #{end_time.strftime('%H:%M')}", category: :error
|
73
97
|
end
|
data/lib/tempo/models/log.rb
CHANGED
@@ -58,6 +58,13 @@ module Tempo
|
|
58
58
|
FileRecord::FileUtility.new(self, options).log_records
|
59
59
|
end
|
60
60
|
|
61
|
+
# returns the loaded record with the latest start time
|
62
|
+
# Only loads records if options[:load] is true
|
63
|
+
def last_record(options={})
|
64
|
+
load_last_day(options) if options[:load]
|
65
|
+
sort_by_start_time.last
|
66
|
+
end
|
67
|
+
|
61
68
|
# send alternate directory through options
|
62
69
|
def save_to_file(options={})
|
63
70
|
FileRecord::Record.save_log(self, options)
|
@@ -65,6 +65,7 @@ module Tempo
|
|
65
65
|
|
66
66
|
# end time cannot be set to :running, only to a
|
67
67
|
# valid Time object
|
68
|
+
# Use running! to restart a time record
|
68
69
|
#
|
69
70
|
def end_time=time
|
70
71
|
raise ArgumentError if !time.kind_of? Time
|
@@ -154,6 +155,11 @@ module Tempo
|
|
154
155
|
@end_time == :running
|
155
156
|
end
|
156
157
|
|
158
|
+
def running!
|
159
|
+
raise "only the most recent record can be reopened" unless self == self.class.last_record
|
160
|
+
@end_time = :running
|
161
|
+
end
|
162
|
+
|
157
163
|
def freeze_dry
|
158
164
|
record = super
|
159
165
|
record[:project_title] = project_title
|
@@ -181,7 +187,7 @@ module Tempo
|
|
181
187
|
|
182
188
|
private
|
183
189
|
|
184
|
-
#close current at the end time, or on the last minute
|
190
|
+
# close current at the end time, or on the last minute
|
185
191
|
# of the day if end time is another day
|
186
192
|
#
|
187
193
|
def self.close_current(end_time)
|
data/lib/tempo/version.rb
CHANGED
data/lib/tempo/views/base.rb
CHANGED
@@ -48,6 +48,14 @@ module Tempo
|
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
+
def message(message)
|
52
|
+
ViewRecords::Message.new message, category: :info
|
53
|
+
end
|
54
|
+
|
55
|
+
def error(message)
|
56
|
+
ViewRecords::Message.new message, category: :error
|
57
|
+
end
|
58
|
+
|
51
59
|
def no_match_error(items, request, plural=true)
|
52
60
|
match = plural ? "match" : "matches"
|
53
61
|
ViewRecords::Message.new "no #{items} #{match} the request: #{request}", category: :error
|
data/lib/time_utilities.rb
CHANGED
@@ -11,21 +11,21 @@ describe Tempo::TimeConflictError do
|
|
11
11
|
|
12
12
|
it "can create a message with a target duration" do
|
13
13
|
@exception = Tempo::TimeConflictError.new @start_time, @end_time, @target_start_time, @target_end_time
|
14
|
-
@exception.to_s.must_equal "time <08:15 - 08:45> conflicts with existing record: 07:15 - 09:15"
|
14
|
+
@exception.to_s.must_equal "time <08:15 - 08:45> conflicts with existing record: 07:15 - 09:15 on Jan 02, 2014"
|
15
15
|
end
|
16
16
|
|
17
17
|
it "can create a message with a target time" do
|
18
18
|
@exception = Tempo::TimeConflictError.new @start_time, @end_time, @target_start_time
|
19
|
-
@exception.to_s.must_equal "time <08:15> conflicts with existing record: 07:15 - 09:15"
|
19
|
+
@exception.to_s.must_equal "time <08:15> conflicts with existing record: 07:15 - 09:15 on Jan 02, 2014"
|
20
20
|
end
|
21
21
|
|
22
22
|
it "can create a message without a target time" do
|
23
23
|
@exception = Tempo::TimeConflictError.new @start_time, @end_time
|
24
|
-
@exception.to_s.must_equal "time conflicts with existing record: 07:15 - 09:15"
|
24
|
+
@exception.to_s.must_equal "time conflicts with existing record: 07:15 - 09:15 on Jan 02, 2014"
|
25
25
|
end
|
26
26
|
|
27
27
|
it "can handle running time entries" do
|
28
28
|
@exception = Tempo::TimeConflictError.new @start_time, :running, @target_start_time
|
29
|
-
@exception.to_s.must_equal "time <08:15> conflicts with existing record: 07:15 - running"
|
29
|
+
@exception.to_s.must_equal "time <08:15> conflicts with existing record: 07:15 - running on Jan 02, 2014"
|
30
30
|
end
|
31
|
-
end
|
31
|
+
end
|
@@ -17,7 +17,6 @@ describe Tempo do
|
|
17
17
|
it "inherits the freeze-dry method" do
|
18
18
|
log_factory
|
19
19
|
frozen = @log_4.freeze_dry
|
20
|
-
binding.pry if @log_4.id != 1
|
21
20
|
frozen.must_equal({ :start_time=>Time.new(2014, 01, 02, 07, 15),
|
22
21
|
:id=>1, :message=>"day 2 pet the sheep"})
|
23
22
|
end
|
@@ -182,5 +181,10 @@ describe Tempo do
|
|
182
181
|
Tempo::Model::MessageLog.days_index[:"20140101"].length.must_equal 2
|
183
182
|
Tempo::Model::MessageLog.days_index[:"20140102"].length.must_equal 3
|
184
183
|
end
|
184
|
+
|
185
|
+
it "can return the last record" do
|
186
|
+
log_factory
|
187
|
+
Tempo::Model::MessageLog.last_record.must_equal @log_6
|
188
|
+
end
|
185
189
|
end
|
186
190
|
end
|
@@ -73,6 +73,19 @@ describe Tempo do
|
|
73
73
|
@record_6.running?.must_equal true
|
74
74
|
end
|
75
75
|
|
76
|
+
it "has a running! method for last record only" do
|
77
|
+
time_record_factory
|
78
|
+
@record_6.end_time = Time.new(2014, 1, 2, 19, 00 )
|
79
|
+
@record_6.running!
|
80
|
+
Tempo::Model::TimeRecord.current.must_equal @record_6
|
81
|
+
end
|
82
|
+
|
83
|
+
it "running! method succeeds on last record only" do
|
84
|
+
time_record_factory
|
85
|
+
proc { @record_1.running!}.must_raise RuntimeError
|
86
|
+
end
|
87
|
+
|
88
|
+
|
76
89
|
it "has a next record method" do
|
77
90
|
time_record_factory
|
78
91
|
@record_1.next_record.must_equal @record_2
|
@@ -155,7 +168,7 @@ describe Tempo do
|
|
155
168
|
|
156
169
|
it "errors when end time is before start time" do
|
157
170
|
Tempo::Model::TimeRecord.clear_all
|
158
|
-
proc { Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 12 ), end_time: Time.new(2014, 1, 1, 10 ) }) }.must_raise
|
171
|
+
proc { Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 12 ), end_time: Time.new(2014, 1, 1, 10 ) }) }.must_raise Tempo::EndTimeError
|
159
172
|
end
|
160
173
|
|
161
174
|
it "accepts and end time equal to start time" do
|
@@ -173,7 +186,7 @@ describe Tempo do
|
|
173
186
|
|
174
187
|
it "errors when end time is on a different day" do
|
175
188
|
Tempo::Model::TimeRecord.clear_all
|
176
|
-
proc { Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 10 ), end_time: Time.new(2014, 1, 2, 12 ) }) }.must_raise
|
189
|
+
proc { Tempo::Model::TimeRecord.new({ start_time: Time.new(2014, 1, 1, 10 ), end_time: Time.new(2014, 1, 2, 12 ) }) }.must_raise Tempo::DifferentDaysError
|
177
190
|
end
|
178
191
|
|
179
192
|
it "errors when end time in existing record" do
|
@@ -212,7 +225,7 @@ describe Tempo do
|
|
212
225
|
@record = Tempo::Model::TimeRecord.new({project: @project_1,
|
213
226
|
start_time: Time.new(2014, 1, 1, 8 ),
|
214
227
|
end_time: Time.new(2014, 1, 1, 10 ) })
|
215
|
-
proc { @record.start_time = Time.new(2014, 1, 1, 11 )}.must_raise
|
228
|
+
proc { @record.start_time = Time.new(2014, 1, 1, 11 )}.must_raise Tempo::EndTimeError
|
216
229
|
|
217
230
|
@record.start_time = Time.new(2014, 1, 1, 9 )
|
218
231
|
@record.start_time.must_equal Time.new(2014, 1, 1, 9 )
|
@@ -225,7 +238,7 @@ describe Tempo do
|
|
225
238
|
start_time: Time.new(2014, 1, 1, 8 ),
|
226
239
|
end_time: Time.new(2014, 1, 1, 10 ) })
|
227
240
|
|
228
|
-
proc { @record.end_time = Time.new(2014, 1, 1, 7 )}.must_raise
|
241
|
+
proc { @record.end_time = Time.new(2014, 1, 1, 7 )}.must_raise Tempo::EndTimeError
|
229
242
|
@record.end_time = Time.new(2014, 1, 1, 11 )
|
230
243
|
@record.end_time.must_equal Time.new(2014, 1, 1, 11 )
|
231
244
|
end
|