timr 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.ackrc +9 -0
  3. data/.editorconfig +1 -0
  4. data/.env.example +7 -0
  5. data/.github/CONTRIBUTING.md +32 -0
  6. data/.github/ISSUE_TEMPLATE.md +13 -0
  7. data/.gitignore +8 -2
  8. data/.rdoc_options +21 -0
  9. data/.travis.yml +10 -7
  10. data/Gemfile +8 -0
  11. data/README.md +216 -3
  12. data/bin/.gitignore +2 -0
  13. data/bin/README.md +17 -0
  14. data/bin/build.sh +14 -0
  15. data/bin/build_api.sh +14 -0
  16. data/bin/build_coverage.sh +23 -0
  17. data/bin/build_info.sh +27 -0
  18. data/bin/build_man.sh +41 -0
  19. data/bin/clean.sh +14 -0
  20. data/bin/dev_setup.sh +19 -0
  21. data/bin/install.sh +49 -0
  22. data/bin/publish +38 -0
  23. data/bin/release.sh +35 -0
  24. data/bin/test.sh +19 -0
  25. data/bin/timr +20 -40
  26. data/bin/timr_bash_completion.sh +337 -0
  27. data/bin/uninstall.sh +24 -0
  28. data/lib/timr.rb +36 -8
  29. data/lib/timr/command/basic_command.rb +170 -0
  30. data/lib/timr/command/continue_command.rb +86 -0
  31. data/lib/timr/command/help_command.rb +137 -0
  32. data/lib/timr/command/log_command.rb +297 -0
  33. data/lib/timr/command/pause_command.rb +89 -0
  34. data/lib/timr/command/pop_command.rb +176 -0
  35. data/lib/timr/command/push_command.rb +141 -0
  36. data/lib/timr/command/report_command.rb +689 -0
  37. data/lib/timr/command/start_command.rb +172 -0
  38. data/lib/timr/command/status_command.rb +198 -0
  39. data/lib/timr/command/stop_command.rb +127 -0
  40. data/lib/timr/command/task_command.rb +318 -0
  41. data/lib/timr/command/track_command.rb +381 -0
  42. data/lib/timr/command/version_command.rb +18 -0
  43. data/lib/timr/duration.rb +159 -0
  44. data/lib/timr/exception/timr_error.rb +113 -0
  45. data/lib/timr/ext/time.rb +12 -0
  46. data/lib/timr/helper/datetime_helper.rb +128 -0
  47. data/lib/timr/helper/terminal_helper.rb +58 -0
  48. data/lib/timr/helper/translation_helper.rb +45 -0
  49. data/lib/timr/model/basic_model.rb +287 -0
  50. data/lib/timr/model/config.rb +48 -0
  51. data/lib/timr/model/foreign_id_db.rb +84 -0
  52. data/lib/timr/model/stack.rb +161 -0
  53. data/lib/timr/model/task.rb +1039 -0
  54. data/lib/timr/model/track.rb +589 -0
  55. data/lib/timr/progressbar.rb +41 -0
  56. data/lib/timr/simple_opt_parser.rb +230 -0
  57. data/lib/timr/status.rb +70 -0
  58. data/lib/timr/table.rb +88 -0
  59. data/lib/timr/timr.rb +500 -558
  60. data/lib/timr/version.rb +4 -15
  61. data/man/.gitignore +2 -0
  62. data/man/_footer +3 -0
  63. data/man/timr-continue.1 +48 -0
  64. data/man/timr-continue.1.ronn +39 -0
  65. data/man/timr-ftime.7 +77 -0
  66. data/man/timr-ftime.7.ronn +57 -0
  67. data/man/timr-log.1 +109 -0
  68. data/man/timr-log.1.ronn +87 -0
  69. data/man/timr-pause.1 +56 -0
  70. data/man/timr-pause.1.ronn +45 -0
  71. data/man/timr-pop.1 +66 -0
  72. data/man/timr-pop.1.ronn +53 -0
  73. data/man/timr-push.1 +25 -0
  74. data/man/timr-push.1.ronn +20 -0
  75. data/man/timr-report.1 +228 -0
  76. data/man/timr-report.1.ronn +193 -0
  77. data/man/timr-start.1 +100 -0
  78. data/man/timr-start.1.ronn +82 -0
  79. data/man/timr-status.1 +53 -0
  80. data/man/timr-status.1.ronn +42 -0
  81. data/man/timr-stop.1 +75 -0
  82. data/man/timr-stop.1.ronn +60 -0
  83. data/man/timr-task.1 +147 -0
  84. data/man/timr-task.1.ronn +115 -0
  85. data/man/timr-track.1 +109 -0
  86. data/man/timr-track.1.ronn +89 -0
  87. data/man/timr.1 +119 -0
  88. data/man/timr.1.ronn +68 -0
  89. data/timr.gemspec +18 -3
  90. data/timr.sublime-project +20 -1
  91. metadata +142 -23
  92. data/Makefile +0 -12
  93. data/Makefile.common +0 -56
  94. data/lib/timr/stack.rb +0 -81
  95. data/lib/timr/task.rb +0 -258
  96. data/lib/timr/track.rb +0 -167
  97. data/lib/timr/window.rb +0 -259
  98. data/lib/timr/window_help.rb +0 -41
  99. data/lib/timr/window_tasks.rb +0 -30
  100. data/lib/timr/window_test.rb +0 -20
  101. data/lib/timr/window_timeline.rb +0 -33
  102. data/tests/tc_stack.rb +0 -121
  103. data/tests/tc_task.rb +0 -190
  104. data/tests/tc_track.rb +0 -144
  105. data/tests/tc_window.rb +0 -428
  106. data/tests/ts_all.rb +0 -6
@@ -0,0 +1,318 @@
1
+
2
+ require 'set'
3
+
4
+ module TheFox
5
+ module Timr
6
+ module Command
7
+
8
+ # - Print informations about a specific [Task](rdoc-ref:TheFox::Timr::Model::Task).
9
+ # - Add/remove a Task.
10
+ # - Edit (set) a Task.
11
+ #
12
+ # Man page: [timr-task(1)](../../../../man/timr-task.1.html)
13
+ class TaskCommand < BasicCommand
14
+
15
+ include TheFox::Timr::Model
16
+ include TheFox::Timr::Helper
17
+ include TheFox::Timr::Error
18
+
19
+ # Path to man page.
20
+ MAN_PATH = 'man/timr-task.1'
21
+
22
+ def initialize(argv = Array.new)
23
+ super()
24
+
25
+ @help_opt = false
26
+ @show_opt = false
27
+ @add_opt = false
28
+ @remove_opt = false
29
+ @set_opt = false
30
+
31
+ @verbose_opt = false
32
+ @tracks_opt = false
33
+
34
+ @foreign_id_opt = nil
35
+ @unset_foreign_id_opt = nil
36
+ @name_opt = nil
37
+ @description_opt = nil
38
+ @estimation_opt = nil
39
+ @billed_opt = nil
40
+ @unbilled_opt = nil
41
+
42
+ @hourly_rate_opt = nil
43
+ @unset_hourly_rate_opt = nil
44
+ @has_flat_rate_opt = nil
45
+ @unset_flat_rate_opt = nil
46
+
47
+ # Holds Task instances.
48
+ @tasks_opt = Set.new
49
+
50
+ loop_c = 0 # Limit the loop.
51
+ while loop_c < 1024 && argv.length > 0
52
+ loop_c += 1
53
+ arg = argv.shift
54
+
55
+ case arg
56
+ when '-h', '--help'
57
+ @help_opt = true
58
+
59
+ when '-v', '--verbose'
60
+ @verbose_opt = true
61
+ when '-t', '--tracks'
62
+ @tracks_opt = true
63
+
64
+ when '--id'
65
+ @foreign_id_opt = argv.shift.strip
66
+ when '--no-id'
67
+ @unset_foreign_id_opt = true
68
+ when '-n', '--name'
69
+ @name_opt = argv.shift
70
+ when '--desc', '--description', '-d' # -d not official
71
+ @description_opt = argv.shift
72
+ when '-e', '--est', '--estimation'
73
+ @estimation_opt = argv.shift
74
+ when '-b', '--billed'
75
+ @billed_opt = true
76
+ when '--unbilled'
77
+ @unbilled_opt = true
78
+
79
+ when '-r', '--hourly-rate'
80
+ @hourly_rate_opt = argv.shift
81
+ when '--no-hourly-rate'
82
+ @unset_hourly_rate_opt = true
83
+ when '--fr', '--flat', '--flat-rate'
84
+ @has_flat_rate_opt = true
85
+ when '--no-flat', '--no-flat-rate'
86
+ @unset_flat_rate_opt = true
87
+
88
+ when 'show'
89
+ @show_opt = true
90
+ when 'add'
91
+ @add_opt = true
92
+ when 'remove'
93
+ @remove_opt = true
94
+ when 'set'
95
+ @set_opt = true
96
+
97
+ when Task
98
+ @tasks_opt << arg
99
+ else
100
+ @tasks_opt << arg
101
+ end
102
+ end
103
+
104
+ if @foreign_id_opt && @unset_foreign_id_opt
105
+ raise TaskCommandError, 'Cannot use --id and --no-id.'
106
+ end
107
+ if @billed_opt && @unbilled_opt
108
+ raise TaskCommandError, 'Cannot use --billed and --unbilled.'
109
+ end
110
+ if !@hourly_rate_opt.nil? && @unset_hourly_rate_opt
111
+ raise TaskCommandError, 'Cannot use --hourly-rate and --no-hourly-rate.'
112
+ end
113
+ if @has_flat_rate_opt && @unset_flat_rate_opt
114
+ raise TaskCommandError, 'Cannot use --flat-rate and --no-flat-rate.'
115
+ end
116
+ end
117
+
118
+ # See BasicCommand#run.
119
+ def run
120
+ if @help_opt
121
+ help
122
+ return
123
+ end
124
+
125
+ @timr = Timr.new(@cwd)
126
+
127
+ if @add_opt
128
+ run_add
129
+ elsif @remove_opt
130
+ run_remove
131
+ elsif @set_opt
132
+ run_set
133
+ else
134
+ if @tasks_opt.count == 0
135
+ run_show_all
136
+ else
137
+ run_show
138
+ end
139
+ end
140
+ end
141
+
142
+ private
143
+
144
+ # Uses TheFox::Timr::Timr.add_task.
145
+ def run_add
146
+ options = {
147
+ :foreign_id => @foreign_id_opt,
148
+ :name => @name_opt,
149
+ :description => @description_opt,
150
+ :estimation => @estimation_opt,
151
+ }
152
+ task = @timr.add_task(options)
153
+
154
+ puts task.to_detailed_str
155
+ end
156
+
157
+ def run_remove
158
+ @tasks_opt.each do |task_id|
159
+ task = @timr.remove_task({:task_id => task_id})
160
+
161
+ tracks_s = TranslationHelper.pluralize(@timr.stack.tracks.count, 'track', 'tracks')
162
+ puts 'Deleted Task %s (%s).' % [task.short_id, tracks_s]
163
+ end
164
+ end
165
+
166
+ def run_set
167
+ if @tasks_opt.count == 0
168
+ raise TaskCommandError, 'No Task ID given.'
169
+ end
170
+ task_id = @tasks_opt.first
171
+
172
+ if @foreign_id_opt.nil? && @unset_foreign_id_opt.nil?
173
+ @name_opt.nil? && @description_opt.nil? &&
174
+ @estimation_opt.nil? &&
175
+ @billed_opt.nil? && @unbilled_opt.nil? &&
176
+ @hourly_rate_opt.nil? && @unset_hourly_rate_opt.nil? &&
177
+ @has_flat_rate_opt.nil? && @unset_flat_rate_opt.nil?
178
+
179
+ raise TaskCommandError, "No option given. See 'time task -h'."
180
+ end
181
+
182
+ task = @timr.get_task_by_id(task_id)
183
+
184
+ puts '--- OLD ---'
185
+ puts task.to_detailed_str
186
+ puts
187
+
188
+ if @foreign_id_opt && task.foreign_id != @foreign_id_opt
189
+ @timr.foreign_id_db.remove_task(task)
190
+
191
+ # Throws exception when Foreign ID already exists in DB.
192
+ # Break before Task save.
193
+ @timr.foreign_id_db.add_task(task, @foreign_id_opt)
194
+ @timr.foreign_id_db.save_to_file
195
+ end
196
+ if @unset_foreign_id_opt
197
+ @timr.foreign_id_db.remove_task(task)
198
+ @timr.foreign_id_db.save_to_file
199
+ end
200
+ if @name_opt
201
+ task.name = @name_opt
202
+ end
203
+ if @description_opt
204
+ task.description = @description_opt
205
+ end
206
+ if @estimation_opt
207
+ task.estimation = @estimation_opt
208
+ end
209
+ if @billed_opt || @unbilled_opt
210
+ if @billed_opt
211
+ task.is_billed = true
212
+ else
213
+ task.is_billed = false
214
+ end
215
+ end
216
+ if @hourly_rate_opt
217
+ task.hourly_rate = @hourly_rate_opt
218
+ end
219
+ if @unset_hourly_rate_opt
220
+ task.hourly_rate = nil
221
+ end
222
+ if @has_flat_rate_opt
223
+ task.has_flat_rate = true
224
+ end
225
+ if @unset_flat_rate_opt
226
+ task.has_flat_rate = false
227
+ end
228
+
229
+ task.save_to_file
230
+
231
+ puts '--- NEW ---'
232
+ puts task.to_detailed_str
233
+ end
234
+
235
+ def run_show
236
+ options = Hash.new
237
+ if @verbose_opt
238
+ options[:full_id] = true
239
+ end
240
+
241
+ tasks = Array.new
242
+ @tasks_opt.each do |task_id_or_instance|
243
+ if task_id_or_instance.is_a?(Task)
244
+ task = task_id_or_instance
245
+ else
246
+ task = @timr.get_task_by_id(task_id_or_instance)
247
+ end
248
+
249
+ tasks << task.to_detailed_array(options)
250
+ end
251
+
252
+ if tasks.count > 0
253
+ puts tasks.map{ |t| t.join("\n") }.join("\n\n")
254
+ end
255
+ end
256
+
257
+ def run_show_all
258
+ @timr.tasks.each do |task_id, task|
259
+ full_id = @verbose_opt ? task.id : task.short_id
260
+
261
+ if task.foreign_id
262
+ puts '%s %s %s' % [full_id, task.foreign_id, task.name_s]
263
+ else
264
+ puts '%s - %s' % [full_id, task.name_s]
265
+ end
266
+ end
267
+ end
268
+
269
+ def help
270
+ puts 'usage: timr task [show] [[-t|--tracks] <id>|<task_id>...]'
271
+ puts ' or: timr task add [--id <str>] [-n|--name <name>] [--description <str>]'
272
+ puts ' [--estimation <time>] [--billed|--unbilled]'
273
+ puts ' [--hourly-rate <float>] [--no-hourly-rate]'
274
+ puts ' [--flat-rate|--no-flat-rate]'
275
+ puts ' or: timr task set [--id <str>] [-n|--name <name>] [--description <str>]'
276
+ puts ' [--estimation <time>] [--billed|--unbilled]'
277
+ puts ' [--hourly-rate <float>] [--no-hourly-rate]'
278
+ puts ' [--flat-rate|--no-flat-rate]'
279
+ puts ' <id>|<task_id>'
280
+ puts ' or: timr task remove <id>|<task_id>...'
281
+ puts ' or: timr task [-h|--help]'
282
+ puts
283
+ puts 'Subcommands'
284
+ puts ' show Default command. When no Task ID is given print all Tasks.'
285
+ puts ' add Add a new Task without starting it.'
286
+ puts ' remove Remove an existing Task.'
287
+ puts ' set Edit an existing Task.'
288
+ puts
289
+ puts 'Show Options'
290
+ puts ' -t, --tracks Show a list of Track IDs for each Task.'
291
+ puts
292
+ puts 'Add/Set Options'
293
+ puts ' --id <str> Your ID to identify the Task.'
294
+ puts ' -n, --name <name> Task Name.'
295
+ puts ' --desc, --description <str> Task Description.'
296
+ puts ' -e, --est, --estimation <time> Task Estimation. See details below.'
297
+ puts ' -b, --billed Mark Task as billed.'
298
+ puts ' --unbilled Mark Task as unbilled.'
299
+ puts ' -r, --hourly-rate <float> Set the Hourly Rate.'
300
+ puts ' --no-hourly-rate Unset Hourly Rate.'
301
+ puts ' --fr, --flat-rate, --flat Has Task a Flat Rate?'
302
+ puts ' --no-flat-rate, --no-flat Unset Flat Rate.'
303
+ puts
304
+ HelpCommand.print_man_units_help
305
+ puts
306
+ HelpCommand.print_estimation_help(true)
307
+ puts
308
+ puts 'Billed/Unbilled'
309
+ puts ' If a whole Task gets billed/unbilled all Tracks are changed to'
310
+ puts " billed/unbilled. Each Track has a flag 'is_billed'."
311
+ puts
312
+ end
313
+
314
+ end # class TaskCommand
315
+
316
+ end # module Command
317
+ end # module Timr
318
+ end # module TheFox
@@ -0,0 +1,381 @@
1
+
2
+ require 'set'
3
+
4
+ module TheFox
5
+ module Timr
6
+ module Command
7
+
8
+ # - Print informations about a specific [Track](rdoc-ref:TheFox::Timr::Model::Track).
9
+ # - Add/remove a Track.
10
+ # - Edit (set) a Track.
11
+ #
12
+ # Man page: [timr-track(1)](../../../../man/timr-track.1.html)
13
+ class TrackCommand < BasicCommand
14
+
15
+ include TheFox::Timr::Model
16
+ include TheFox::Timr::Error
17
+
18
+ # Path to man page.
19
+ MAN_PATH = 'man/timr-track.1'
20
+
21
+ def initialize(argv = Array.new)
22
+ super()
23
+
24
+ @help_opt = false
25
+ @show_opt = false
26
+ @add_opt = false
27
+ @remove_opt = false
28
+ @set_opt = false
29
+
30
+ @verbose_opt = false
31
+ @tracks_opt = Set.new
32
+ @task_opt = false
33
+ @task_id_opt = nil
34
+
35
+ @message_opt = nil
36
+ @start_date_opt = nil
37
+ @start_time_opt = nil
38
+ @end_date_opt = nil
39
+ @end_time_opt = nil
40
+ @billed_opt = nil
41
+ @unbilled_opt = nil
42
+
43
+ loop_c = 0 # Limit the loop.
44
+ while loop_c < 1024 && argv.length > 0
45
+ loop_c += 1
46
+ arg = argv.shift
47
+
48
+ case arg
49
+ when '-h', '--help'
50
+ @help_opt = true
51
+
52
+ when '-v', '--verbose'
53
+ @verbose_opt = true
54
+ when '-t', '--task'
55
+ if @set_opt
56
+ @task_id_opt = argv.shift
57
+ else
58
+ @task_opt = true
59
+ end
60
+
61
+ when '-m', '--message'
62
+ @message_opt = argv.shift
63
+ when '--sd', '--start-date'
64
+ @start_date_opt = argv.shift
65
+ when '--st', '--start-time'
66
+ @start_time_opt = argv.shift
67
+ when '--ed', '--end-date'
68
+ @end_date_opt = argv.shift
69
+ when '--et', '--end-time'
70
+ @end_time_opt = argv.shift
71
+ when '-b', '--billed'
72
+ @billed_opt = true
73
+ when '--unbilled'
74
+ @unbilled_opt = true
75
+
76
+ when 'show'
77
+ @show_opt = true
78
+ when 'add'
79
+ @add_opt = true
80
+ when 'remove'
81
+ @remove_opt = true
82
+ when 'set'
83
+ @set_opt = true
84
+
85
+ else
86
+ @tracks_opt << arg
87
+ end
88
+ end
89
+
90
+ if @billed_opt && @unbilled_opt
91
+ raise TrackCommandError, 'Cannot use --billed and --unbilled.'
92
+ end
93
+ end
94
+
95
+ # See BasicCommand#run.
96
+ def run
97
+ if @help_opt
98
+ help
99
+ return
100
+ end
101
+
102
+ @timr = Timr.new(@cwd)
103
+ @timr.load_all_tracks
104
+
105
+ if @task_opt
106
+ run_task_command
107
+ elsif @add_opt
108
+ run_add
109
+ elsif @remove_opt
110
+ run_remove
111
+ elsif @set_opt
112
+ run_set
113
+ else
114
+ run_show
115
+ end
116
+ end
117
+
118
+ private
119
+
120
+ def run_task_command
121
+ tasks = Hash.new # Set.new
122
+
123
+ @tracks_opt.each do |track_id|
124
+ track = @timr.get_track_by_id(track_id)
125
+ task = track.task
126
+
127
+ unless tasks.has_key?(task.id)
128
+ tasks[task.id] = task
129
+ end
130
+ end
131
+
132
+ task_command_args = tasks.values
133
+
134
+ if @verbose_opt
135
+ task_command_args << '--verbose'
136
+ end
137
+
138
+ task_command = TaskCommand.new(task_command_args)
139
+ task_command.run
140
+ end
141
+
142
+ def run_show
143
+ options = Hash.new
144
+ if @verbose_opt
145
+ options[:full_id] = true
146
+ end
147
+
148
+ tracks = Array.new
149
+ @tracks_opt.each do |track_id|
150
+ track = @timr.get_track_by_id(track_id)
151
+ unless track
152
+ raise TrackCommandError, "Track for ID '#{track_id}' not found."
153
+ end
154
+
155
+ tracks << track.to_detailed_array(options)
156
+ end
157
+
158
+ if tracks.count > 0
159
+ puts tracks.map{ |track_s| track_s.join("\n") }.join("\n\n")
160
+ end
161
+ end
162
+
163
+ def run_add
164
+ task_id = check_task_id
165
+
166
+ check_opts_add
167
+
168
+ task = @timr.get_task_by_id(task_id)
169
+
170
+ track = Track.new
171
+ if @start_date_opt && @start_time_opt
172
+ track.begin_datetime = Time.parse("#{@start_date_opt} #{@start_time_opt}")
173
+ end
174
+ if @end_date_opt && @end_time_opt
175
+ track.end_datetime = Time.parse("#{@end_date_opt} #{@end_time_opt}")
176
+ end
177
+ if @message_opt
178
+ track.message = @message_opt
179
+ end
180
+ if @billed_opt || @unbilled_opt
181
+ if @billed_opt
182
+ track.is_billed = true
183
+ else
184
+ track.is_billed = false
185
+ end
186
+ end
187
+
188
+ task.add_track(track)
189
+ task.save_to_file
190
+
191
+ puts track.to_detailed_str
192
+ end
193
+
194
+ def run_remove
195
+ @tracks_opt.each do |track_id|
196
+ task_track_h = @timr.remove_track({:track_id => track_id})
197
+
198
+ task = task_track_h[:task]
199
+ track = task_track_h[:track]
200
+
201
+ puts 'Deleted Track %s from Task %s.' % [track.short_id, task.short_id]
202
+ end
203
+ end
204
+
205
+ def run_set
206
+ track_id = check_track_id
207
+
208
+ check_opts_set
209
+
210
+ track = @timr.get_track_by_id(track_id)
211
+ unless track
212
+ raise TrackError, "Track for ID '#{track_id}' not found."
213
+ end
214
+
215
+ puts '--- OLD ---'
216
+ puts track.to_detailed_str
217
+ puts
218
+
219
+ bdt = track.begin_datetime
220
+ edt = track.end_datetime
221
+
222
+ # Start DateTime
223
+ if @start_date_opt && @start_time_opt
224
+ track.begin_datetime = "#{@start_date_opt}T#{@start_time_opt}"
225
+ elsif @start_date_opt.nil? && @start_time_opt
226
+ if bdt
227
+ track.begin_datetime = "#{bdt.strftime('%F')}T#{@start_time_opt}"
228
+ else
229
+ raise TrackCommandError, 'Start Date must be given. Track has no Start DateTime.'
230
+ end
231
+ elsif @start_date_opt && @start_time_opt.nil?
232
+ if bdt
233
+ track.begin_datetime = "#{@start_date_opt}T#{bdt.strftime('%T%z')}"
234
+ else
235
+ raise TrackCommandError, 'Start Time must be given. Track has no Start DateTime.'
236
+ end
237
+ # elsif @start_date_opt.nil? && @start_time_opt.nil?
238
+ # raise TrackCommandError, 'Start Date or Start Time must be given.'
239
+ end
240
+
241
+ # End DateTime
242
+ if @end_date_opt && @end_time_opt
243
+ track.end_datetime = "#{@end_date_opt}T#{@end_time_opt}"
244
+ elsif @end_date_opt.nil? && @end_time_opt
245
+ if edt
246
+ track.end_datetime = "#{edt.strftime('%F')}T#{@end_time_opt}"
247
+ else
248
+ raise TrackCommandError, 'End Date must be given. Track has no End DateTime.'
249
+ end
250
+ elsif @end_date_opt && @end_time_opt.nil?
251
+ if edt
252
+ track.end_datetime = "#{@end_date_opt}T#{edt.strftime('%T%z')}"
253
+ else
254
+ raise TrackCommandError, 'End Time must be given. Track has no End DateTime.'
255
+ end
256
+ # elsif @end_date_opt.nil? && @end_time_opt.nil?
257
+ # raise TrackCommandError, 'End Date or End Time must be given.'
258
+ end
259
+
260
+ # Message
261
+ if @message_opt
262
+ track.message = @message_opt
263
+ end
264
+
265
+ # Billed / Unbilled
266
+ if @billed_opt || @unbilled_opt
267
+ if @billed_opt
268
+ track.is_billed = true
269
+ else
270
+ track.is_billed = false
271
+ end
272
+ end
273
+
274
+ task = track.task
275
+
276
+ if @task_id_opt
277
+ target_task = @timr.get_task_by_id(@task_id_opt)
278
+
279
+ task.move_track(track, target_task)
280
+
281
+ target_task.save_to_file
282
+
283
+ if @timr.stack.on_stack?(track)
284
+ @timr.stack.changed
285
+ @timr.stack.save_to_file
286
+ end
287
+ end
288
+
289
+ task.save_to_file
290
+
291
+ puts '--- NEW ---'
292
+ puts track.to_detailed_str
293
+ end
294
+
295
+ def check_task_id
296
+ if @tracks_opt.count == 0
297
+ raise TrackCommandError, 'No Task ID given.'
298
+ end
299
+ @tracks_opt.first
300
+ end
301
+
302
+ def check_track_id
303
+ if @tracks_opt.count == 0
304
+ raise TrackCommandError, 'No Track ID given.'
305
+ end
306
+ @tracks_opt.first
307
+ end
308
+
309
+ def check_opts_add
310
+ if @start_date_opt || @start_time_opt ||
311
+ @end_date_opt || @end_time_opt
312
+
313
+ if @start_date_opt.nil?
314
+ raise TrackCommandError, 'Start Date must be given.'
315
+ end
316
+ if @start_time_opt.nil?
317
+ raise TrackCommandError, 'Start Time must be given.'
318
+ end
319
+
320
+ if @end_date_opt.nil?
321
+ raise TrackCommandError, 'End Date must be given.'
322
+ end
323
+ if @end_time_opt.nil?
324
+ raise TrackCommandError, 'End Time must be given.'
325
+ end
326
+ end
327
+ end
328
+
329
+ def check_opts_set
330
+ if @start_date_opt.nil? && @start_time_opt.nil? &&
331
+ @end_date_opt.nil? && @end_time_opt.nil? &&
332
+ @message_opt.nil? && @task_id_opt.nil? &&
333
+ @billed_opt.nil? && @unbilled_opt.nil?
334
+
335
+ raise TrackCommandError, "No option given. See 'timr track --help'."
336
+ end
337
+ end
338
+
339
+ def help
340
+ puts 'usage: timr track [show] [-t|--task] <track_id>...'
341
+ puts ' or: timr track add [-m|--message <message>]'
342
+ puts ' [--start-date <date> --start-time <time>'
343
+ puts ' [--end-date <date> --end-time <time>]]'
344
+ puts ' [--billed|--unbilled] <id>|<task_id>'
345
+ puts ' or: timr track set [-m|--message <message>]'
346
+ puts ' [--start-date <date> --start-time <time>]'
347
+ puts ' [--end-date <date> --end-time <time>]'
348
+ puts ' [-t|--task <id>|<task_id>] [--billed|--unbilled]'
349
+ puts ' <track_id>'
350
+ puts ' or: timr track remove <track_id>...'
351
+ puts ' or: timr track [-h|--help]'
352
+ puts
353
+ puts 'Show Options'
354
+ puts " -t, --task Show Task of Track. Same as 'timr task <task_id>'."
355
+ puts
356
+ puts 'Add/Set Options'
357
+ puts ' -m, --message <message> Track Message. What have you done?'
358
+ puts ' --sd, --start-date <date> Start Date'
359
+ puts ' --st, --start-time <time> Start Time'
360
+ puts ' --ed, --end-date <date> End Date'
361
+ puts ' --et, --end-time <time> End Time'
362
+ puts ' -b, --billed Mark Track as billed.'
363
+ puts ' --unbilled Mark Track as unbilled.'
364
+ puts
365
+ puts 'Set Options'
366
+ puts ' --task <id>|<task_id> Move Track to another Task.'
367
+ puts
368
+ puts 'Start DateTime must be given when End DateTime is given. A Track cannot have a'
369
+ puts 'End DateTime without a Start DateTime.'
370
+ puts
371
+ HelpCommand.print_man_units_help
372
+ puts
373
+ HelpCommand.print_datetime_help
374
+ puts
375
+ end
376
+
377
+ end # class TrackCommand
378
+
379
+ end # module Command
380
+ end # module Timr
381
+ end # module TheFox