tempo-cli 0.1.6 → 0.2.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.
- checksums.yaml +7 -0
- data/Gemfile.lock +3 -3
- data/README.md +9 -3
- data/bin/tempo +20 -2
- data/features/arrange.feature +1 -1
- data/features/directory.feature +108 -0
- data/features/project.feature +2 -2
- data/features/report.feature +3 -2
- data/features/start.feature +0 -1
- data/features/step_definitions/tempo_steps.rb +99 -20
- data/features/update.feature +7 -1
- data/lib/file_record/directory.rb +19 -3
- data/lib/file_record/file_utility.rb +122 -0
- data/lib/file_record/record.rb +36 -83
- data/lib/tempo/controllers/arrange_controller.rb +5 -5
- data/lib/tempo/controllers/base.rb +8 -8
- data/lib/tempo/controllers/checkout_controller.rb +4 -4
- data/lib/tempo/controllers/end_controller.rb +4 -5
- data/lib/tempo/controllers/projects_controller.rb +13 -10
- data/lib/tempo/controllers/records_controller.rb +8 -5
- data/lib/tempo/controllers/report_controller.rb +4 -4
- data/lib/tempo/controllers/start_controller.rb +4 -3
- data/lib/tempo/controllers/update_controller.rb +22 -8
- data/lib/tempo/exceptions.rb +2 -2
- data/lib/tempo/models/base.rb +26 -18
- data/lib/tempo/models/composite.rb +5 -3
- data/lib/tempo/models/log.rb +61 -38
- data/lib/tempo/models/project.rb +9 -6
- data/lib/tempo/models/time_record.rb +14 -14
- data/lib/tempo/version.rb +1 -1
- data/lib/tempo/views/arrange_view.rb +4 -4
- data/lib/tempo/views/base.rb +10 -23
- data/lib/tempo/views/formatters/base.rb +2 -2
- data/lib/tempo/views/formatters/screen.rb +7 -7
- data/lib/tempo/views/projects_view.rb +8 -8
- data/lib/tempo/views/report_view.rb +5 -5
- data/lib/tempo/views/reporter.rb +4 -4
- data/lib/tempo/views/time_record_view.rb +5 -5
- data/lib/tempo/views/view_records/base.rb +8 -8
- data/lib/tempo/views/view_records/composite.rb +4 -4
- data/lib/tempo/views/view_records/log.rb +3 -3
- data/lib/tempo/views/view_records/project.rb +3 -3
- data/lib/tempo/views/view_records/time_record.rb +5 -5
- data/lib/tempo.rb +3 -0
- data/lib/time_utilities.rb +4 -4
- data/tempo-cli.gemspec +8 -7
- data/test/lib/file_record/directory_test.rb +14 -1
- data/test/lib/file_record/record_test.rb +40 -75
- data/test/lib/tempo/models/base_test.rb +2 -2
- data/test/lib/tempo/models/composite_test.rb +9 -9
- data/test/lib/tempo/models/log_test.rb +31 -16
- data/test/lib/tempo/models/time_record_test.rb +29 -19
- data/test/support/factories.rb +5 -0
- data/test/support/helpers.rb +7 -7
- metadata +40 -53
data/lib/tempo/models/base.rb
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
# The Base model class, from which all other models are derived.
|
4
|
+
# Models are given a unique id, which is stored in the class index.
|
5
|
+
# FileRecord handles all file storage and retrieval. Options are passed
|
6
|
+
# through to FileRecord for the purpose of sending in an alternative directory.
|
7
|
+
# example: options = {directory: "my_directory"} will save to Users/username/my_directory.
|
8
|
+
#
|
9
|
+
|
1
10
|
module Tempo
|
2
11
|
module Model
|
3
12
|
|
@@ -29,18 +38,20 @@ module Tempo
|
|
29
38
|
|
30
39
|
# example: Tempo::Model::Animal -> tempo_animals.yaml
|
31
40
|
def file
|
32
|
-
FileRecord::
|
41
|
+
FileRecord::FileUtility.new(self).filename
|
33
42
|
end
|
34
43
|
|
35
|
-
|
36
|
-
|
44
|
+
# pass custom directory through in options
|
45
|
+
def save_to_file(options={})
|
46
|
+
FileRecord::Record.save_model self, options
|
37
47
|
end
|
38
48
|
|
39
|
-
|
40
|
-
|
49
|
+
# pass custom directory through in options
|
50
|
+
def read_from_file(options={})
|
51
|
+
FileRecord::Record.read_model self, options
|
41
52
|
end
|
42
53
|
|
43
|
-
def method_missing
|
54
|
+
def method_missing(meth, *args, &block)
|
44
55
|
|
45
56
|
if meth.to_s =~ /^find_by_(.+)$/
|
46
57
|
run_find_by_method($1, *args, &block)
|
@@ -52,14 +63,14 @@ module Tempo
|
|
52
63
|
end
|
53
64
|
end
|
54
65
|
|
55
|
-
def run_sort_by_method
|
66
|
+
def run_sort_by_method(attribute, args=@index.clone, &block)
|
56
67
|
attr = "@#{attribute}".to_sym
|
57
68
|
args.sort! { |a,b| a.instance_variable_get( attr ) <=> b.instance_variable_get( attr ) }
|
58
69
|
return args unless block
|
59
70
|
block.call args
|
60
71
|
end
|
61
72
|
|
62
|
-
def run_find_by_method
|
73
|
+
def run_find_by_method(attrs, *args, &block)
|
63
74
|
# Make an array of attribute names
|
64
75
|
attrs = attrs.split('_and_')
|
65
76
|
|
@@ -79,14 +90,14 @@ module Tempo
|
|
79
90
|
end
|
80
91
|
|
81
92
|
# find by id should be exact, so we remove the array wrapper
|
82
|
-
def find_by_id
|
93
|
+
def find_by_id(id)
|
83
94
|
matches = find "id", id
|
84
95
|
match = matches[0]
|
85
96
|
end
|
86
97
|
|
87
98
|
# example: Tempo::Model.find("id", 1)
|
88
99
|
#
|
89
|
-
def find
|
100
|
+
def find(key, value)
|
90
101
|
key = "@#{key}".to_sym
|
91
102
|
matches = []
|
92
103
|
index.each do |i|
|
@@ -106,14 +117,14 @@ module Tempo
|
|
106
117
|
matches
|
107
118
|
end
|
108
119
|
|
109
|
-
def delete
|
120
|
+
def delete(instance)
|
110
121
|
id = instance.id
|
111
122
|
index.delete( instance )
|
112
123
|
ids.delete( id )
|
113
124
|
end
|
114
|
-
end
|
125
|
+
end # class methods
|
115
126
|
|
116
|
-
def initialize
|
127
|
+
def initialize(options={})
|
117
128
|
id_candidate = options[:id]
|
118
129
|
if !id_candidate
|
119
130
|
@id = self.class.next_id
|
@@ -133,9 +144,6 @@ module Tempo
|
|
133
144
|
state.each do |attr|
|
134
145
|
key = attr[1..-1].to_sym
|
135
146
|
val = instance_variable_get attr
|
136
|
-
|
137
|
-
#val = val.to_s if val.kind_of? Time
|
138
|
-
|
139
147
|
record[key] = val
|
140
148
|
end
|
141
149
|
record
|
@@ -147,13 +155,13 @@ module Tempo
|
|
147
155
|
|
148
156
|
protected
|
149
157
|
|
150
|
-
def self.add_to_index
|
158
|
+
def self.add_to_index(member)
|
151
159
|
@index ||= []
|
152
160
|
@index << member
|
153
161
|
@index.sort! { |a,b| a.id <=> b.id }
|
154
162
|
end
|
155
163
|
|
156
|
-
def self.add_id
|
164
|
+
def self.add_id(id)
|
157
165
|
@ids ||=[]
|
158
166
|
@ids << id
|
159
167
|
@ids.sort!
|
@@ -1,8 +1,10 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
1
3
|
# Composite Model extends base to accomodate tree structures
|
2
4
|
# Each instance can be a root instance, or a child of another
|
3
5
|
# instance, and each instance can have any number of children.
|
4
6
|
# report_trees is a utility method for testing the validity of the
|
5
|
-
# model, and
|
7
|
+
# model, and can be used as a template for creating tree reports.
|
6
8
|
|
7
9
|
module Tempo
|
8
10
|
module Model
|
@@ -26,7 +28,7 @@ module Tempo
|
|
26
28
|
report_array += "]"
|
27
29
|
end
|
28
30
|
|
29
|
-
def delete
|
31
|
+
def delete(instance)
|
30
32
|
instance.children.each do |child_id|
|
31
33
|
child = find_by_id child_id
|
32
34
|
instance.remove_child child
|
@@ -47,7 +49,7 @@ module Tempo
|
|
47
49
|
child.parent = self.id
|
48
50
|
end
|
49
51
|
|
50
|
-
def remove_child(
|
52
|
+
def remove_child(child)
|
51
53
|
@children.delete child.id
|
52
54
|
child.parent = :root
|
53
55
|
end
|
data/lib/tempo/models/log.rb
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
# Log extends base by allowing models to be associated with a time instance.
|
4
|
+
# Ids are only unique by day, and each model also has a day id. Together these
|
5
|
+
# two ids assure uniquness. When saved, each day is recorded as it's own file.
|
6
|
+
|
1
7
|
module Tempo
|
2
8
|
module Model
|
3
9
|
class Log < Tempo::Model::Base
|
@@ -12,13 +18,14 @@ module Tempo
|
|
12
18
|
# id counter is managed through the private methods
|
13
19
|
# increase_id_counter and next_id below
|
14
20
|
#
|
15
|
-
def id_counter
|
21
|
+
def id_counter(time)
|
16
22
|
dsym = date_symbol time
|
17
23
|
@id_counter = {} unless @id_counter.kind_of? Hash
|
18
24
|
@id_counter[ dsym ] ||= 1
|
19
25
|
end
|
20
26
|
|
21
|
-
|
27
|
+
# Returns an array of ids for the given day
|
28
|
+
def ids(time)
|
22
29
|
dsym = date_symbol time
|
23
30
|
@ids = {} unless @ids.kind_of? Hash
|
24
31
|
@ids[dsym] ||= []
|
@@ -33,68 +40,85 @@ module Tempo
|
|
33
40
|
@days_index
|
34
41
|
end
|
35
42
|
|
36
|
-
|
37
|
-
|
43
|
+
# Passthrough function, returns the log filename for a given date
|
44
|
+
#
|
45
|
+
def file(time)
|
46
|
+
FileRecord::FileUtility.new(self, {time: time}).filename
|
38
47
|
end
|
39
48
|
|
49
|
+
# Returns the immediate directory for the log
|
50
|
+
# Tempo::Model::MessageLog => tempo_message_logs
|
40
51
|
def dir
|
41
|
-
FileRecord::
|
52
|
+
FileRecord::FileUtility.new(self).log_directory
|
42
53
|
end
|
43
54
|
|
44
|
-
|
45
|
-
|
46
|
-
|
55
|
+
# Load all records from a directory into an array
|
56
|
+
# send alternate directory through options
|
57
|
+
def records(options={})
|
58
|
+
FileRecord::FileUtility.new(self, options).log_records
|
47
59
|
end
|
48
60
|
|
49
|
-
|
50
|
-
|
61
|
+
# send alternate directory through options
|
62
|
+
def save_to_file(options={})
|
63
|
+
FileRecord::Record.save_log(self, options)
|
51
64
|
end
|
52
65
|
|
53
|
-
|
54
|
-
def read_from_file
|
66
|
+
# send alternate directory through options
|
67
|
+
def read_from_file(time, options={})
|
55
68
|
dsym = date_symbol time
|
56
69
|
@days_index[ dsym ] = [] if not days_index.has_key? dsym
|
57
|
-
FileRecord::Record.read_log(
|
70
|
+
FileRecord::Record.read_log(self, time, options)
|
58
71
|
end
|
59
72
|
|
60
73
|
# load all the records for a single day
|
61
74
|
#
|
62
|
-
def load_day_record
|
75
|
+
def load_day_record(time, options={})
|
63
76
|
dsym = date_symbol time
|
64
77
|
if not days_index.has_key? dsym
|
65
78
|
@days_index[ dsym ] = []
|
66
|
-
read_from_file time
|
79
|
+
read_from_file time, options
|
67
80
|
end
|
68
81
|
end
|
69
82
|
|
70
83
|
# load the records for each day from time 1 to time 2
|
71
84
|
#
|
72
|
-
def load_days_records
|
85
|
+
def load_days_records(time_1, time_2, options={})
|
73
86
|
|
74
87
|
return if time_1.nil? || time_2.nil?
|
75
88
|
|
76
|
-
days = (
|
89
|
+
days = (time_2.to_date - time_1.to_date).to_i
|
77
90
|
return if days < 0
|
78
91
|
|
79
|
-
(days + 1).times { |i| load_day_record(
|
92
|
+
(days + 1).times { |i| load_day_record(time_1.add_days(i), options)}
|
80
93
|
end
|
81
94
|
|
82
95
|
# load the records for the most recently recorded day
|
83
96
|
#
|
84
|
-
def load_last_day
|
97
|
+
def load_last_day(options={})
|
85
98
|
reg = /(\d+)\.yaml/
|
86
|
-
|
87
|
-
|
99
|
+
recs = records(options)
|
100
|
+
if recs.last
|
101
|
+
d_id = reg.match(recs.last)[1]
|
88
102
|
time = day_id_to_time d_id if d_id
|
89
|
-
load_day_record time
|
103
|
+
load_day_record time, options
|
90
104
|
return time
|
91
105
|
end
|
92
106
|
end
|
93
107
|
|
108
|
+
# delete the file for a single day
|
109
|
+
# this is necessary for removing a single entry on a day
|
110
|
+
# since updates will skip over days with no entries
|
111
|
+
#
|
112
|
+
def delete_day_record(time, options={})
|
113
|
+
options[:time] = time
|
114
|
+
options[:destroy] = true
|
115
|
+
FileRecord::FileUtility.new(self, options).file_path
|
116
|
+
end
|
117
|
+
|
94
118
|
# takes and integer, and time or day_id
|
95
119
|
# and returns the instance that matches both
|
96
120
|
# the id and d_id
|
97
|
-
def find_by_id
|
121
|
+
def find_by_id(id, time)
|
98
122
|
time = day_id time
|
99
123
|
ids = find "id", id
|
100
124
|
d_ids = find "d_id", time
|
@@ -107,19 +131,18 @@ module Tempo
|
|
107
131
|
# day_ids can be run through without change
|
108
132
|
# Time will be converted into "YYYYmmdd"
|
109
133
|
# ex: 1-1-2014 => "20140101"
|
110
|
-
def day_id
|
111
|
-
if time.
|
112
|
-
|
113
|
-
end
|
134
|
+
def day_id(time)
|
135
|
+
return time if time.to_s =~ /^\d{8}$/
|
136
|
+
|
114
137
|
raise ArgumentError, "Invalid Time" if not time.kind_of? Time
|
115
138
|
time.strftime("%Y%m%d")
|
116
139
|
end
|
117
140
|
|
118
|
-
def day_id_to_time
|
141
|
+
def day_id_to_time(d_id)
|
119
142
|
time = Time.new(d_id[0..3].to_i, d_id[4..5].to_i, d_id[6..7].to_i)
|
120
143
|
end
|
121
144
|
|
122
|
-
def delete
|
145
|
+
def delete(instance)
|
123
146
|
id = instance.id
|
124
147
|
dsym = date_symbol instance.d_id
|
125
148
|
|
@@ -129,8 +152,8 @@ module Tempo
|
|
129
152
|
end
|
130
153
|
end
|
131
154
|
|
132
|
-
def initialize(
|
133
|
-
@start_time = options.fetch(:start_time, Time.now
|
155
|
+
def initialize(options={})
|
156
|
+
@start_time = options.fetch(:start_time, Time.now)
|
134
157
|
@start_time = Time.new(@start_time) if @start_time.kind_of? String
|
135
158
|
|
136
159
|
self.class.load_day_record(@start_time)
|
@@ -139,7 +162,7 @@ module Tempo
|
|
139
162
|
id_candidate = options[:id]
|
140
163
|
if !id_candidate
|
141
164
|
@id = self.class.next_id @start_time
|
142
|
-
elsif self.class.ids(
|
165
|
+
elsif self.class.ids(@start_time).include? id_candidate
|
143
166
|
raise IdentityConflictError, "Id #{id_candidate} already exists"
|
144
167
|
else
|
145
168
|
@id = id_candidate
|
@@ -160,7 +183,7 @@ module Tempo
|
|
160
183
|
|
161
184
|
class << self
|
162
185
|
|
163
|
-
def add_to_days_index
|
186
|
+
def add_to_days_index(member)
|
164
187
|
@days_index = {} unless @days_index.kind_of? Hash
|
165
188
|
dsym = date_symbol member.start_time
|
166
189
|
@days_index[dsym] ||= []
|
@@ -168,7 +191,7 @@ module Tempo
|
|
168
191
|
@days_index[dsym].sort! { |a,b| a.start_time <=> b.start_time }
|
169
192
|
end
|
170
193
|
|
171
|
-
def add_id
|
194
|
+
def add_id(time, id)
|
172
195
|
dsym = date_symbol time
|
173
196
|
@ids = {} unless @ids.kind_of? Hash
|
174
197
|
@ids[dsym] ||= []
|
@@ -176,18 +199,18 @@ module Tempo
|
|
176
199
|
@ids[dsym].sort!
|
177
200
|
end
|
178
201
|
|
179
|
-
def date_symbol
|
180
|
-
day_id(
|
202
|
+
def date_symbol(time)
|
203
|
+
day_id(time).to_sym
|
181
204
|
end
|
182
205
|
|
183
|
-
def increase_id_counter
|
206
|
+
def increase_id_counter(time)
|
184
207
|
dsym = date_symbol time
|
185
208
|
@id_counter = {} unless @id_counter.kind_of? Hash
|
186
209
|
@id_counter[ dsym ] ||= 0
|
187
210
|
@id_counter[ dsym ] = @id_counter[ dsym ].next
|
188
211
|
end
|
189
212
|
|
190
|
-
def next_id
|
213
|
+
def next_id(time)
|
191
214
|
while ids(time).include? id_counter time
|
192
215
|
increase_id_counter time
|
193
216
|
end
|
data/lib/tempo/models/project.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
1
3
|
module Tempo
|
2
4
|
module Model
|
3
5
|
class Project < Tempo::Model::Composite
|
@@ -7,11 +9,11 @@ module Tempo
|
|
7
9
|
|
8
10
|
class << self
|
9
11
|
|
10
|
-
def current(
|
12
|
+
def current(instance=nil)
|
11
13
|
@current
|
12
14
|
end
|
13
15
|
|
14
|
-
def current=(
|
16
|
+
def current=(instance)
|
15
17
|
if instance.class == self
|
16
18
|
@current = instance
|
17
19
|
else
|
@@ -19,8 +21,8 @@ module Tempo
|
|
19
21
|
end
|
20
22
|
end
|
21
23
|
|
22
|
-
def include?(
|
23
|
-
matches = find_by_title(
|
24
|
+
def include?(title)
|
25
|
+
matches = find_by_title(title)
|
24
26
|
return false if matches.empty?
|
25
27
|
matches.each do |match|
|
26
28
|
return true if match.title == title
|
@@ -42,6 +44,7 @@ module Tempo
|
|
42
44
|
self.class.current == self
|
43
45
|
end
|
44
46
|
|
47
|
+
# record the active project by adding current = true
|
45
48
|
def freeze_dry
|
46
49
|
record = super
|
47
50
|
if self.class.current == self
|
@@ -50,7 +53,7 @@ module Tempo
|
|
50
53
|
record
|
51
54
|
end
|
52
55
|
|
53
|
-
def tag(
|
56
|
+
def tag(tags)
|
54
57
|
return unless tags and tags.kind_of? Array
|
55
58
|
tags.each do |tag|
|
56
59
|
tag.split.each {|t| @tags << t if ! @tags.include? t }
|
@@ -58,7 +61,7 @@ module Tempo
|
|
58
61
|
@tags.sort!
|
59
62
|
end
|
60
63
|
|
61
|
-
def untag(
|
64
|
+
def untag(tags)
|
62
65
|
return unless tags and tags.kind_of? Array
|
63
66
|
tags.each do |tag|
|
64
67
|
tag.split.each {|t| @tags.delete t }
|
@@ -30,7 +30,7 @@ module Tempo
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
def initialize
|
33
|
+
def initialize(options={})
|
34
34
|
|
35
35
|
# declare these first for model organization when sent to YAML
|
36
36
|
@project_title = nil
|
@@ -54,7 +54,7 @@ module Tempo
|
|
54
54
|
leave_only_one_running
|
55
55
|
end
|
56
56
|
|
57
|
-
def start_time=
|
57
|
+
def start_time=time
|
58
58
|
raise ArgumentError if !time.kind_of? Time
|
59
59
|
if @end_time != :running
|
60
60
|
@start_time = time if verify_times time, @end_time
|
@@ -66,7 +66,7 @@ module Tempo
|
|
66
66
|
# end time cannot be set to :running, only to a
|
67
67
|
# valid Time object
|
68
68
|
#
|
69
|
-
def end_time=
|
69
|
+
def end_time=time
|
70
70
|
raise ArgumentError if !time.kind_of? Time
|
71
71
|
@end_time = time if verify_times self.start_time, time
|
72
72
|
end
|
@@ -74,7 +74,7 @@ module Tempo
|
|
74
74
|
# method for updating both times at once, necessary if it would
|
75
75
|
# cause a conflict to do them individually
|
76
76
|
#
|
77
|
-
def update_times
|
77
|
+
def update_times(start_time, end_time)
|
78
78
|
raise ArgumentError if !start_time.kind_of? Time
|
79
79
|
raise ArgumentError if !end_time.kind_of? Time
|
80
80
|
verify_times start_time, end_time
|
@@ -86,7 +86,7 @@ module Tempo
|
|
86
86
|
# Public method to access verify start time,
|
87
87
|
# determine if an error will be raised
|
88
88
|
#
|
89
|
-
def valid_start_time?
|
89
|
+
def valid_start_time?(time)
|
90
90
|
return false if !time.kind_of? Time
|
91
91
|
begin
|
92
92
|
if @end_time != :running
|
@@ -103,7 +103,7 @@ module Tempo
|
|
103
103
|
# Public method to access verify end time,
|
104
104
|
# determine if an error will be raised
|
105
105
|
#
|
106
|
-
def valid_end_time?
|
106
|
+
def valid_end_time?(time)
|
107
107
|
return false if !time.kind_of? Time
|
108
108
|
begin
|
109
109
|
verify_times self.start_time, time
|
@@ -160,7 +160,7 @@ module Tempo
|
|
160
160
|
record
|
161
161
|
end
|
162
162
|
|
163
|
-
def tag
|
163
|
+
def tag(tags)
|
164
164
|
return unless tags and tags.kind_of? Array
|
165
165
|
tags.each do |tag|
|
166
166
|
tag.split.each {|t| @tags << t if ! @tags.include? t }
|
@@ -168,7 +168,7 @@ module Tempo
|
|
168
168
|
@tags.sort!
|
169
169
|
end
|
170
170
|
|
171
|
-
def untag
|
171
|
+
def untag(tags)
|
172
172
|
return unless tags and tags.kind_of? Array
|
173
173
|
tags.each do |tag|
|
174
174
|
tag.split.each {|t| @tags.delete t }
|
@@ -184,7 +184,7 @@ module Tempo
|
|
184
184
|
#close current at the end time, or on the last minute
|
185
185
|
# of the day if end time is another day
|
186
186
|
#
|
187
|
-
def self.close_current
|
187
|
+
def self.close_current(end_time)
|
188
188
|
if end_time.day > current.start_time.day
|
189
189
|
out = end_of_day current.start_time
|
190
190
|
current.end_time = out
|
@@ -254,7 +254,7 @@ module Tempo
|
|
254
254
|
# check a time against all loaded instances, verify that it doesn't
|
255
255
|
# fall in the middle of any closed time records
|
256
256
|
#
|
257
|
-
def verify_start_time
|
257
|
+
def verify_start_time(time)
|
258
258
|
|
259
259
|
# Check that there are currently
|
260
260
|
# records on the day to iterate through
|
@@ -278,7 +278,7 @@ module Tempo
|
|
278
278
|
# end time of :running. This condition, (currently only possible from init)
|
279
279
|
# requires a second check to close out all but the most recent time entry.
|
280
280
|
#
|
281
|
-
def verify_times
|
281
|
+
def verify_times(start_time, end_time)
|
282
282
|
|
283
283
|
verify_start_time start_time
|
284
284
|
|
@@ -307,7 +307,7 @@ module Tempo
|
|
307
307
|
#
|
308
308
|
# It will return true if it is exactly the record start or end time
|
309
309
|
#
|
310
|
-
def time_in_record?
|
310
|
+
def time_in_record?(time, record)
|
311
311
|
return false if record.end_time == :running
|
312
312
|
time >= record.start_time && time <= record.end_time
|
313
313
|
end
|
@@ -318,7 +318,7 @@ module Tempo
|
|
318
318
|
# this condition must be accounted for separately.
|
319
319
|
# It assumes a valid start and end time.
|
320
320
|
#
|
321
|
-
def time_span_intersects_record?
|
321
|
+
def time_span_intersects_record?(start_time, end_time, record)
|
322
322
|
if record.end_time == :running
|
323
323
|
return true if start_time <= record.start_time && end_time > record.start_time
|
324
324
|
return false
|
@@ -332,7 +332,7 @@ module Tempo
|
|
332
332
|
|
333
333
|
# returns the last minute of the day
|
334
334
|
#
|
335
|
-
def self.end_of_day
|
335
|
+
def self.end_of_day(time)
|
336
336
|
Time.new(time.year, time.month, time.day, 23, 59)
|
337
337
|
end
|
338
338
|
end
|
data/lib/tempo/version.rb
CHANGED
@@ -2,19 +2,19 @@ module Tempo
|
|
2
2
|
module Views
|
3
3
|
class << self
|
4
4
|
|
5
|
-
def arrange_parent_child
|
5
|
+
def arrange_parent_child(parent, child)
|
6
6
|
ViewRecords::Message.new "parent project:"
|
7
7
|
ViewRecords::Project.new parent
|
8
8
|
ViewRecords::Message.new "child project:"
|
9
9
|
ViewRecords::Project.new child
|
10
10
|
end
|
11
11
|
|
12
|
-
def arrange_root
|
12
|
+
def arrange_root(project)
|
13
13
|
ViewRecords::Message.new "root project:"
|
14
14
|
ViewRecords::Project.new project
|
15
15
|
end
|
16
16
|
|
17
|
-
def arrange_already_root
|
17
|
+
def arrange_already_root(project)
|
18
18
|
ViewRecords::Message.new "already a root project:"
|
19
19
|
ViewRecords::Project.new project
|
20
20
|
end
|
@@ -24,4 +24,4 @@ module Tempo
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
27
|
-
end
|
27
|
+
end
|
data/lib/tempo/views/base.rb
CHANGED
@@ -3,7 +3,7 @@ module Tempo
|
|
3
3
|
class << self
|
4
4
|
|
5
5
|
# called in the pre block, pushes relavent options to the reporter
|
6
|
-
def initialize_view_options
|
6
|
+
def initialize_view_options(command, global_options, options)
|
7
7
|
view_opts = {}
|
8
8
|
view_opts[:verbose] = global_options[:verbose]
|
9
9
|
view_opts[:id] = global_options[:id]
|
@@ -26,24 +26,7 @@ module Tempo
|
|
26
26
|
Tempo::Views::Reporter.add_options view_opts
|
27
27
|
end
|
28
28
|
|
29
|
-
|
30
|
-
#
|
31
|
-
# puts each line if output=true
|
32
|
-
# else returns an array of view lines
|
33
|
-
def return_view( view, options={} )
|
34
|
-
output = options.fetch( :output, true )
|
35
|
-
|
36
|
-
if output
|
37
|
-
if view.is_a? String
|
38
|
-
puts view
|
39
|
-
else
|
40
|
-
view.each { |line| puts line }
|
41
|
-
end
|
42
|
-
end
|
43
|
-
view
|
44
|
-
end
|
45
|
-
|
46
|
-
def options_report( command, global_options, options, args )
|
29
|
+
def options_report(command, global_options, options, args)
|
47
30
|
globals_list = "global options: "
|
48
31
|
global_options.each {|k,v| globals_list += "#{k} = #{v}, " if k.kind_of? String and k.length > 1 and !v.nil? }
|
49
32
|
ViewRecords::Message.new globals_list[0..-2], category: :debug
|
@@ -57,20 +40,24 @@ module Tempo
|
|
57
40
|
ViewRecords::Message.new "args: #{args}", category: :debug
|
58
41
|
end
|
59
42
|
|
60
|
-
def no_items(
|
43
|
+
def no_items(items, category=:info)
|
61
44
|
ViewRecords::Message.new "no #{items} exist", category: category
|
45
|
+
if items == "projects"
|
46
|
+
ViewRecords::Message.new "You must at least one project before you can begin tracking time"
|
47
|
+
ViewRecords::Message.new "run `tempo project --help` for more information"
|
48
|
+
end
|
62
49
|
end
|
63
50
|
|
64
|
-
def no_match_error(
|
51
|
+
def no_match_error(items, request, plural=true)
|
65
52
|
match = plural ? "match" : "matches"
|
66
53
|
ViewRecords::Message.new "no #{items} #{match} the request: #{request}", category: :error
|
67
54
|
end
|
68
55
|
|
69
|
-
def already_exists_error(
|
56
|
+
def already_exists_error(item, request)
|
70
57
|
ViewRecords::Message.new "#{item} '#{request}' already exists", category: :error
|
71
58
|
end
|
72
59
|
|
73
|
-
def checkout_assistance(
|
60
|
+
def checkout_assistance(options={})
|
74
61
|
ViewRecords::Message.new "checkout command run with no arguments"
|
75
62
|
ViewRecords::Message.new "perhaps you meant one of these?"
|
76
63
|
ViewRecords::Message.new " tempo checkout --add <new project name>"
|
@@ -17,7 +17,7 @@ module Tempo
|
|
17
17
|
# record type. See View Records for all possible record types. See screen formatter
|
18
18
|
# for examples of proc blocks.
|
19
19
|
#
|
20
|
-
def format_records
|
20
|
+
def format_records(records, options={})
|
21
21
|
@options = options
|
22
22
|
records.each do |record|
|
23
23
|
class_block = "#{record.type}_block"
|
@@ -27,4 +27,4 @@ module Tempo
|
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
30
|
-
end
|
30
|
+
end
|