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.
Files changed (55) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile.lock +3 -3
  3. data/README.md +9 -3
  4. data/bin/tempo +20 -2
  5. data/features/arrange.feature +1 -1
  6. data/features/directory.feature +108 -0
  7. data/features/project.feature +2 -2
  8. data/features/report.feature +3 -2
  9. data/features/start.feature +0 -1
  10. data/features/step_definitions/tempo_steps.rb +99 -20
  11. data/features/update.feature +7 -1
  12. data/lib/file_record/directory.rb +19 -3
  13. data/lib/file_record/file_utility.rb +122 -0
  14. data/lib/file_record/record.rb +36 -83
  15. data/lib/tempo/controllers/arrange_controller.rb +5 -5
  16. data/lib/tempo/controllers/base.rb +8 -8
  17. data/lib/tempo/controllers/checkout_controller.rb +4 -4
  18. data/lib/tempo/controllers/end_controller.rb +4 -5
  19. data/lib/tempo/controllers/projects_controller.rb +13 -10
  20. data/lib/tempo/controllers/records_controller.rb +8 -5
  21. data/lib/tempo/controllers/report_controller.rb +4 -4
  22. data/lib/tempo/controllers/start_controller.rb +4 -3
  23. data/lib/tempo/controllers/update_controller.rb +22 -8
  24. data/lib/tempo/exceptions.rb +2 -2
  25. data/lib/tempo/models/base.rb +26 -18
  26. data/lib/tempo/models/composite.rb +5 -3
  27. data/lib/tempo/models/log.rb +61 -38
  28. data/lib/tempo/models/project.rb +9 -6
  29. data/lib/tempo/models/time_record.rb +14 -14
  30. data/lib/tempo/version.rb +1 -1
  31. data/lib/tempo/views/arrange_view.rb +4 -4
  32. data/lib/tempo/views/base.rb +10 -23
  33. data/lib/tempo/views/formatters/base.rb +2 -2
  34. data/lib/tempo/views/formatters/screen.rb +7 -7
  35. data/lib/tempo/views/projects_view.rb +8 -8
  36. data/lib/tempo/views/report_view.rb +5 -5
  37. data/lib/tempo/views/reporter.rb +4 -4
  38. data/lib/tempo/views/time_record_view.rb +5 -5
  39. data/lib/tempo/views/view_records/base.rb +8 -8
  40. data/lib/tempo/views/view_records/composite.rb +4 -4
  41. data/lib/tempo/views/view_records/log.rb +3 -3
  42. data/lib/tempo/views/view_records/project.rb +3 -3
  43. data/lib/tempo/views/view_records/time_record.rb +5 -5
  44. data/lib/tempo.rb +3 -0
  45. data/lib/time_utilities.rb +4 -4
  46. data/tempo-cli.gemspec +8 -7
  47. data/test/lib/file_record/directory_test.rb +14 -1
  48. data/test/lib/file_record/record_test.rb +40 -75
  49. data/test/lib/tempo/models/base_test.rb +2 -2
  50. data/test/lib/tempo/models/composite_test.rb +9 -9
  51. data/test/lib/tempo/models/log_test.rb +31 -16
  52. data/test/lib/tempo/models/time_record_test.rb +29 -19
  53. data/test/support/factories.rb +5 -0
  54. data/test/support/helpers.rb +7 -7
  55. metadata +40 -53
@@ -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::Record.model_filename self
41
+ FileRecord::FileUtility.new(self).filename
33
42
  end
34
43
 
35
- def save_to_file
36
- FileRecord::Record.save_model self
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
- def read_from_file
40
- FileRecord::Record.read_model self
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 meth, *args, &block
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 attribute, args=@index.clone, &block
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 attrs, *args, &block
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 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 key, value
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 instance
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 options={}
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 member
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 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 cam be used as a template for creating tree reports.
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 instance
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( child )
52
+ def remove_child(child)
51
53
  @children.delete child.id
52
54
  child.parent = :root
53
55
  end
@@ -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 time
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
- def ids time
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
- def file time
37
- FileRecord::Record.log_filename( self, time )
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::Record.log_dirname( self )
52
+ FileRecord::FileUtility.new(self).log_directory
42
53
  end
43
54
 
44
- def records
45
- path = FileRecord::Record.log_dir( self )
46
- Dir[path + "/*.yaml"]
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
- def save_to_file
50
- FileRecord::Record.save_log( self )
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 time
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( self, time )
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 time
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 time_1, time_2
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 = ( time_2.to_date - time_1.to_date ).to_i
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( time_1.add_days( i ))}
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
- if records.last
87
- d_id = reg.match(records.last)[1] if records.last
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 id, time
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 time
111
- if time.kind_of? String
112
- return time if time =~ /^\d{8}$/
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 d_id
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 instance
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( options={} )
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( @start_time ).include? id_candidate
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 member
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 time, 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 time
180
- day_id( time ).to_sym
202
+ def date_symbol(time)
203
+ day_id(time).to_sym
181
204
  end
182
205
 
183
- def increase_id_counter time
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 time
213
+ def next_id(time)
191
214
  while ids(time).include? id_counter time
192
215
  increase_id_counter time
193
216
  end
@@ -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( instance=nil )
12
+ def current(instance=nil)
11
13
  @current
12
14
  end
13
15
 
14
- def current=( instance )
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?( title )
23
- matches = find_by_title( 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( tags )
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( tags )
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 options={}
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= 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= 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 start_time, end_time
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? 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? 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 tags
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 tags
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 end_time
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 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 start_time, end_time
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? time, 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? start_time, end_time, 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 time
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
@@ -1,3 +1,3 @@
1
1
  module Tempo
2
- VERSION = '0.1.6'
2
+ VERSION = '0.2.1'
3
3
  end
@@ -2,19 +2,19 @@ module Tempo
2
2
  module Views
3
3
  class << self
4
4
 
5
- def arrange_parent_child 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 project
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 project
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
@@ -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 command, global_options, 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
- # DEPRACATE- View is returned in post
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( items, category=:info )
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( items, request, plural=true )
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( item, request )
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( options={} )
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 records, options={}
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