timr 0.3.0 → 0.4.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.
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