syc-task 0.3.2 → 1.0.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.
- checksums.yaml +5 -13
- data/README.rdoc +73 -30
- data/bin/console_timer +1 -1
- data/bin/syctask +7 -38
- data/lib/syctask/environment.rb +157 -151
- data/lib/syctask/evaluator.rb +21 -1
- data/lib/syctask/scanner.rb +14 -4
- data/lib/syctask/schedule.rb +126 -118
- data/lib/syctask/settings.rb +6 -4
- data/lib/syctask/statistics.rb +6 -0
- data/lib/syctask/task.rb +91 -82
- data/lib/syctask/task_planner.rb +52 -16
- data/lib/syctask/task_scheduler.rb +3 -3
- data/lib/syctask/task_service.rb +13 -10
- data/lib/syctask/task_tracker.rb +12 -6
- data/lib/syctask/version.rb +2 -2
- data/lib/syctime/time_util.rb +62 -11
- data/lib/sycutil/console_timer.rb +5 -9
- metadata +198 -149
data/lib/syctask/schedule.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
|
-
require_relative 'times
|
2
|
-
require_relative 'meeting
|
3
|
-
require_relative '../sycstring/string_util
|
4
|
-
require_relative '../syctime/time_util
|
1
|
+
require_relative 'times'
|
2
|
+
require_relative 'meeting'
|
3
|
+
require_relative '../sycstring/string_util'
|
4
|
+
require_relative '../syctime/time_util'
|
5
5
|
|
6
6
|
include Sycstring
|
7
7
|
include Syctime
|
8
8
|
|
9
9
|
module Syctask
|
10
|
-
|
11
10
|
# Schedule represents a working day with a start and end time, meeting times
|
12
11
|
# and titles and tasks. Tasks can also be associated to meetings as in an
|
13
12
|
# agenda.
|
@@ -18,7 +17,7 @@ module Syctask
|
|
18
17
|
# tasks = [task1,task2,task3,task4,task5,task6]
|
19
18
|
# schedule = Syctask::Schedule.new(work,busy,titles,tasks)
|
20
19
|
# schedule.graph.each {|output| puts output}
|
21
|
-
#
|
20
|
+
#
|
22
21
|
# This will create following output
|
23
22
|
# Meetings
|
24
23
|
# --------
|
@@ -28,7 +27,7 @@ module Syctask
|
|
28
27
|
# A B
|
29
28
|
# xxoo/////xxx|-////oooooxoooo|---|---|---|---|
|
30
29
|
# 8 9 10 11 12 13 14 15 16 17 18 19
|
31
|
-
# 1 2 3 4 5
|
30
|
+
# 1 2 3 4 5
|
32
31
|
# 6
|
33
32
|
#
|
34
33
|
# Tasks
|
@@ -39,7 +38,7 @@ module Syctask
|
|
39
38
|
# 3 - 4: task4
|
40
39
|
# 4 - 5: task5
|
41
40
|
# 5 - 6: task6
|
42
|
-
#
|
41
|
+
#
|
43
42
|
# Subsequent tasks are are displayed in the graph alternating with x and o.
|
44
43
|
# Meetings are indicated with / and the start is marked with A, B and so on.
|
45
44
|
# Task IDs are shown below the graph. The graph will be printed colored.
|
@@ -55,14 +54,14 @@ module Syctask
|
|
55
54
|
# If tasks cannot be assigned to the working time this color is used
|
56
55
|
UNSCHEDULED_COLOR = :yellow
|
57
56
|
# Regex scans tasks and free times in the graph
|
58
|
-
GRAPH_PATTERN =
|
57
|
+
GRAPH_PATTERN = %r{[|-]+|/+|[xo]+}
|
59
58
|
# Regex scans meetings in the graph
|
60
|
-
BUSY_PATTERN =
|
59
|
+
BUSY_PATTERN = %r{/+}
|
61
60
|
# Regex scans free times in the graph
|
62
|
-
FREE_PATTERN = /[
|
61
|
+
FREE_PATTERN = /[|-]+/
|
63
62
|
# Regex scans tasks in the graph
|
64
63
|
WORK_PATTERN = /[xo]+/
|
65
|
-
|
64
|
+
|
66
65
|
# Start time of working day
|
67
66
|
attr_reader :starts
|
68
67
|
# End time of working day
|
@@ -79,19 +78,21 @@ module Syctask
|
|
79
78
|
# * busy time: [[start_hour, start_minute, end_hour, end_minute],[...]]
|
80
79
|
# * titles: [title,...]
|
81
80
|
# * tasks: [task,...]
|
82
|
-
def initialize(work_time, busy_time=[], titles=[], tasks=[])
|
81
|
+
def initialize(work_time, busy_time = [], titles = [], tasks = [])
|
83
82
|
@starts = Syctask::Times.new([work_time[0], work_time[1]])
|
84
83
|
@ends = Syctask::Times.new([work_time[2], work_time[3]])
|
85
84
|
@meetings = []
|
86
85
|
titles ||= []
|
87
|
-
busy_time.each.with_index do |busy,index|
|
88
|
-
title = titles[index]
|
89
|
-
@meetings << Syctask::Meeting.new(busy, title)
|
86
|
+
busy_time.each.with_index do |busy, index|
|
87
|
+
title = titles[index] || "Meeting #{index}"
|
88
|
+
@meetings << Syctask::Meeting.new(busy, title)
|
89
|
+
end
|
90
|
+
unless within?(@meetings,
|
91
|
+
@starts,
|
92
|
+
@ends)
|
93
|
+
raise Exception,
|
94
|
+
'Busy times have to be within work time'
|
90
95
|
end
|
91
|
-
raise Exception,
|
92
|
-
"Busy times have to be within work time" unless within?(@meetings,
|
93
|
-
@starts,
|
94
|
-
@ends)
|
95
96
|
@tasks = tasks
|
96
97
|
end
|
97
98
|
|
@@ -99,12 +100,13 @@ module Syctask
|
|
99
100
|
# Returns true if succeeds
|
100
101
|
def assign(assignments)
|
101
102
|
assignments.each do |assignment|
|
102
|
-
number = assignment[0].upcase.ord -
|
103
|
-
return false if number
|
103
|
+
number = assignment[0].upcase.ord - 'A'.ord
|
104
|
+
return false if number.negative? || number > @meetings.size
|
105
|
+
|
104
106
|
@meetings[number].tasks.clear
|
105
107
|
assignment[1].split(',').each do |id|
|
106
|
-
index = @tasks.find_index{|task| task.id == id.to_i}
|
107
|
-
@meetings[number].tasks << @tasks[index] if index
|
108
|
+
index = @tasks.find_index { |task| task.id == id.to_i }
|
109
|
+
@meetings[number].tasks << @tasks[index] if index && @tasks[index]
|
108
110
|
end
|
109
111
|
@meetings[number].tasks.uniq!
|
110
112
|
end
|
@@ -113,46 +115,46 @@ module Syctask
|
|
113
115
|
|
114
116
|
# Creates a meeting list for printing. Returns the meeting list
|
115
117
|
def meeting_list
|
116
|
-
list =
|
117
|
-
list <<
|
118
|
-
meeting_number =
|
118
|
+
list = format('%s', "Meetings\n").color(:red)
|
119
|
+
list << format('%s', "--------\n").color(:red)
|
120
|
+
meeting_number = 'A'
|
119
121
|
@meetings.each do |meeting|
|
120
|
-
hint =
|
121
|
-
hint =
|
122
|
-
meeting.starts.time,
|
122
|
+
hint = '-'
|
123
|
+
hint = '*' if time_between?(Time.now,
|
124
|
+
meeting.starts.time,
|
123
125
|
meeting.ends.time)
|
124
|
-
list <<
|
125
|
-
|
126
|
-
|
126
|
+
list << format("%s %s %s\n", meeting_number,
|
127
|
+
hint,
|
128
|
+
meeting.title).color(:red)
|
127
129
|
meeting_number.next!
|
128
130
|
meeting.tasks.each do |task|
|
129
131
|
task_color = task.done? ? :green : :blue
|
130
|
-
list <<
|
132
|
+
list << format("%5s - %s\n", task.id, task.title).color(task_color)
|
131
133
|
end
|
132
|
-
end
|
134
|
+
end
|
133
135
|
list
|
134
136
|
end
|
135
137
|
|
136
138
|
# Creates a meeting caption and returns it for printing
|
137
139
|
def meeting_caption
|
138
|
-
|
139
|
-
caption =
|
140
|
-
meeting_number =
|
140
|
+
(_, meeting_times) = get_times
|
141
|
+
caption = ''
|
142
|
+
meeting_number = 'A'
|
141
143
|
meeting_times.each do |times|
|
142
|
-
caption << ' ' * (times[0] - caption.size) + meeting_number
|
144
|
+
caption << ' ' * (times[0] - caption.size) + meeting_number
|
143
145
|
meeting_number.next!
|
144
146
|
end
|
145
|
-
|
147
|
+
format('%s', caption).color(:red)
|
146
148
|
end
|
147
149
|
|
148
150
|
# Creates the time caption for the time line
|
149
151
|
def time_caption
|
150
152
|
work_time = get_times[0]
|
151
|
-
caption =
|
153
|
+
caption = ''
|
152
154
|
work_time[0].upto(work_time[1]) do |time|
|
153
155
|
caption << time.to_s + (time < 9 ? ' ' * 3 : ' ' * 2)
|
154
156
|
end
|
155
|
-
|
157
|
+
format('%s', caption)
|
156
158
|
end
|
157
159
|
|
158
160
|
# graph first creates creates the time line. Then the busy times are added.
|
@@ -169,35 +171,35 @@ module Syctask
|
|
169
171
|
# * return time line, task caption, task list, meeting caption and meeting
|
170
172
|
# list
|
171
173
|
def graph
|
172
|
-
work_time, meeting_times = get_times
|
174
|
+
(work_time, meeting_times) = get_times
|
173
175
|
|
174
|
-
heading =
|
175
|
-
|
176
|
-
|
176
|
+
heading = format('+++ %s - %s-%s +++', Time.now.strftime('%Y-%m-%d'),
|
177
|
+
@starts.time.strftime('%H:%M'),
|
178
|
+
@ends.time.strftime('%H:%M')).color(:blue)
|
177
179
|
|
178
|
-
time_line =
|
180
|
+
time_line = '|---' * (work_time[1] - work_time[0]) + '|'
|
179
181
|
meeting_times.each do |time|
|
180
|
-
time_line[time[0]..time[1]-1] = '/' * (time[1] - time[0])
|
182
|
+
time_line[time[0]..time[1] - 1] = '/' * (time[1] - time[0])
|
181
183
|
end
|
182
184
|
|
183
185
|
task_list, task_caption = assign_tasks_to_graph(time_line)
|
184
186
|
|
185
187
|
[heading.center(80), meeting_list, meeting_caption,
|
186
|
-
colorize(time_line), time_caption,
|
188
|
+
colorize(time_line), time_caption,
|
187
189
|
task_caption, task_list]
|
188
190
|
end
|
189
191
|
|
190
|
-
private
|
192
|
+
private
|
191
193
|
|
192
194
|
# Checks if meetings are within work times. Returns true if fullfilled
|
193
195
|
# otherwise false
|
194
196
|
def within?(meetings, starts, ends)
|
195
197
|
meetings.each do |meeting|
|
196
198
|
return false if meeting.starts.h < starts.h
|
197
|
-
return false if meeting.starts.h == starts.h
|
198
|
-
meeting.starts.m < starts.m
|
199
|
+
return false if meeting.starts.h == starts.h &&
|
200
|
+
meeting.starts.m < starts.m
|
199
201
|
return false if meeting.ends.h > ends.h
|
200
|
-
return false if meeting.ends.h == ends.h
|
202
|
+
return false if meeting.ends.h == ends.h &&
|
201
203
|
meeting.ends.m > ends.m
|
202
204
|
end
|
203
205
|
true
|
@@ -207,11 +209,13 @@ module Syctask
|
|
207
209
|
# past time is colored black
|
208
210
|
def colorize(time_line)
|
209
211
|
time_line, future = split_time_line(time_line)
|
210
|
-
future
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
212
|
+
if future
|
213
|
+
future.scan(GRAPH_PATTERN) do |part|
|
214
|
+
time_line << format('%s', part).color(BUSY_COLOR) unless part.scan(BUSY_PATTERN).empty?
|
215
|
+
time_line << format('%s', part).color(FREE_COLOR) unless part.scan(FREE_PATTERN).empty?
|
216
|
+
time_line << format('%s', part).color(WORK_COLOR) unless part.scan(WORK_PATTERN).empty?
|
217
|
+
end
|
218
|
+
end
|
215
219
|
time_line
|
216
220
|
end
|
217
221
|
|
@@ -220,11 +224,11 @@ module Syctask
|
|
220
224
|
def split_time_line(time_line)
|
221
225
|
time = Time.now
|
222
226
|
if time.hour < @starts.h
|
223
|
-
past =
|
227
|
+
past = ''
|
224
228
|
future = time_line
|
225
229
|
else
|
226
|
-
offset = (time.hour - @starts.h) * 4 + time.min.div(15)
|
227
|
-
past = time_line.slice(0,offset)
|
230
|
+
offset = (time.hour - @starts.h) * 4 + time.min.div(15)
|
231
|
+
past = time_line.slice(0, offset)
|
228
232
|
future = time_line.slice(offset, time_line.size - offset)
|
229
233
|
end
|
230
234
|
[past, future]
|
@@ -233,18 +237,18 @@ module Syctask
|
|
233
237
|
# Assigns the tasks to the timeline in alternation x and o subsequent tasks.
|
234
238
|
# Returns the task list and the task caption
|
235
239
|
def assign_tasks_to_graph(time_line)
|
236
|
-
done_tasks = []
|
240
|
+
done_tasks = []
|
237
241
|
unscheduled_tasks = []
|
238
|
-
signs = [
|
242
|
+
signs = %w[x o]
|
239
243
|
positions = {}
|
240
244
|
current_time = Time.now
|
241
245
|
unassigned_tasks.each.with_index do |task, index|
|
242
|
-
if task.done?
|
246
|
+
if task.done? || !task.today?
|
243
247
|
done_tasks << task
|
244
248
|
next
|
245
249
|
else
|
246
|
-
round = task.remaining.to_i % 900
|
247
|
-
duration = [(task.remaining.to_i/900+round).round, 1].max
|
250
|
+
round = (task.remaining.to_i % 900).zero? ? 0 : 0.5
|
251
|
+
duration = [(task.remaining.to_i / 900 + round).round, 1].max
|
248
252
|
position = [0, position_for_time(current_time)].max
|
249
253
|
end
|
250
254
|
free_time = scan_free(time_line, 1, position)
|
@@ -252,9 +256,10 @@ module Syctask
|
|
252
256
|
unscheduled_tasks << task
|
253
257
|
next
|
254
258
|
end
|
255
|
-
0.upto(duration-1) do |i|
|
259
|
+
0.upto(duration - 1) do |i|
|
256
260
|
break unless free_time[i]
|
257
|
-
|
261
|
+
|
262
|
+
time_line[free_time[i]] = signs[index % 2]
|
258
263
|
end
|
259
264
|
positions[free_time[0]] = task.id
|
260
265
|
end
|
@@ -262,15 +267,16 @@ module Syctask
|
|
262
267
|
unless done_tasks.empty?
|
263
268
|
end_position = position_for_time(current_time)
|
264
269
|
total_duration = 0
|
265
|
-
done_tasks.each_with_index do |task,index|
|
270
|
+
done_tasks.each_with_index do |task, index|
|
266
271
|
free_time = scan_free(time_line, 1, 0, end_position)
|
267
272
|
lead_time = task.duration.to_i - task.remaining.to_i + 0.0
|
268
273
|
max_duration = [free_time.size - (done_tasks.size - index - 1), 1].max
|
269
|
-
duration = [(lead_time/900).round, 1].max
|
274
|
+
duration = [(lead_time / 900).round, 1].max
|
270
275
|
total_duration += duration = [duration, max_duration].min
|
271
|
-
0.upto(duration-1) do |i|
|
276
|
+
0.upto(duration - 1) do |i|
|
272
277
|
break unless free_time[i]
|
273
|
-
|
278
|
+
|
279
|
+
time_line[free_time[i]] = signs[index % 2]
|
274
280
|
end
|
275
281
|
positions[free_time[0]] = task.id if free_time[0]
|
276
282
|
end
|
@@ -278,50 +284,50 @@ module Syctask
|
|
278
284
|
|
279
285
|
# Create task list
|
280
286
|
max_id_size = 1
|
281
|
-
@tasks.each {|task| max_id_size = [task.id.to_s.size, max_id_size].max}
|
287
|
+
@tasks.each { |task| max_id_size = [task.id.to_s.size, max_id_size].max }
|
282
288
|
max_ord_size = (@tasks.size - 1).to_s.size
|
283
289
|
|
284
|
-
task_list =
|
285
|
-
task_list <<
|
290
|
+
task_list = format('%s', "Tasks\n").color(:blue)
|
291
|
+
task_list << format('%s', "-----\n").color(:blue)
|
286
292
|
@tasks.each.with_index do |task, i|
|
287
|
-
if task.done? or
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
hint =
|
296
|
-
hint =
|
297
|
-
hint =
|
293
|
+
color = if task.done? or !task.today?
|
294
|
+
:green
|
295
|
+
elsif unscheduled_tasks.find_index(task)
|
296
|
+
UNSCHEDULED_COLOR
|
297
|
+
else
|
298
|
+
WORK_COLOR
|
299
|
+
end
|
300
|
+
|
301
|
+
hint = '-'
|
302
|
+
hint = '~' unless task.today?
|
303
|
+
hint = '*' if task.tracked?
|
298
304
|
|
299
305
|
offset = max_ord_size + max_id_size + 5
|
300
|
-
title = split_lines(task.title, 80-offset)
|
301
|
-
title = title.chomp.gsub(/\n/, "\n#{' '*offset}")
|
302
|
-
title <<
|
303
|
-
task_list <<
|
304
|
-
|
306
|
+
title = split_lines(task.title, 80 - offset)
|
307
|
+
title = title.chomp.gsub(/\n/, "\n#{' ' * offset}")
|
308
|
+
title << '>' unless task.options[:note].nil?
|
309
|
+
task_list << format("%#{max_ord_size}d: %#{max_id_size}s %s %s\n",
|
310
|
+
i, task.id, hint, title).color(color)
|
305
311
|
end
|
306
312
|
|
307
313
|
# Create task caption
|
308
|
-
task_caption =
|
309
|
-
create_caption(positions).each do |caption|
|
310
|
-
task_caption <<
|
314
|
+
task_caption = ''
|
315
|
+
create_caption(positions).each do |caption|
|
316
|
+
task_caption << format("%s\n", caption).color(WORK_COLOR)
|
311
317
|
end
|
312
318
|
|
313
319
|
[task_list, task_caption]
|
314
|
-
|
315
320
|
end
|
316
321
|
|
317
322
|
# creates the caption of the graph with hours in 1 hour steps and task IDs
|
318
323
|
# that indicate where in the schedule a task is scheduled.
|
319
324
|
def create_caption(positions)
|
320
325
|
counter = 0
|
321
|
-
lines = [
|
322
|
-
positions.each do |position,id|
|
326
|
+
lines = ['']
|
327
|
+
positions.each do |position, id|
|
323
328
|
next unless position
|
324
|
-
|
329
|
+
|
330
|
+
line_id = next_line(position, lines, counter)
|
325
331
|
legend = ' ' * [0, position - lines[line_id].size].max + id.to_s
|
326
332
|
lines[line_id] += legend
|
327
333
|
counter += 1
|
@@ -333,20 +339,21 @@ module Syctask
|
|
333
339
|
# task ID of a previous task. The effect is shown below
|
334
340
|
# |xx-|//o|x--|
|
335
341
|
# 8 9 10 10
|
336
|
-
# 10 101
|
342
|
+
# 10 101
|
337
343
|
# 11 2
|
338
344
|
# position is the position (time) within the schedule
|
339
345
|
# lines is the available ID lines (above we have 2 ID lines)
|
340
346
|
# counter is the currently displayed line. IDs are displayed alternating in
|
341
347
|
# each line, when we have 2 lines IDs will be printed in line 1,2,1,2...
|
342
348
|
def next_line(position, lines, counter)
|
343
|
-
line = lines[counter%lines.size]
|
344
|
-
return counter%lines.size if line.size == 0
|
349
|
+
line = lines[counter % lines.size]
|
350
|
+
return counter % lines.size if line.size == 0 || line.size < position - 1
|
351
|
+
|
345
352
|
lines.each.with_index do |line, index|
|
346
353
|
return index if line.size < position - 1
|
347
354
|
end
|
348
|
-
lines <<
|
349
|
-
|
355
|
+
lines << ''
|
356
|
+
lines.size - 1
|
350
357
|
end
|
351
358
|
|
352
359
|
# Determines the position within the time line for the given time. Each
|
@@ -362,12 +369,12 @@ module Syctask
|
|
362
369
|
# Scans the schedule for free time where a task can be added to. Count
|
363
370
|
# specifies the length of the free time and the position where to start
|
364
371
|
# scanning within the graph
|
365
|
-
def scan_free(graph, count, starts, ends=graph.size)
|
366
|
-
pattern =
|
372
|
+
def scan_free(graph, count, starts, ends = graph.size)
|
373
|
+
pattern = %r{(?!/)[|-]{#{count}}(?<=-|\||/)}
|
367
374
|
|
368
375
|
positions = []
|
369
376
|
index = starts
|
370
|
-
while index
|
377
|
+
while index && index < ends
|
371
378
|
index = graph.index(pattern, index)
|
372
379
|
if index
|
373
380
|
positions << index if index < ends
|
@@ -387,7 +394,7 @@ module Syctask
|
|
387
394
|
|
388
395
|
unassigned = []
|
389
396
|
unassigned << @tasks
|
390
|
-
unassigned.flatten.delete_if {|task| assigned.find_index(task)}
|
397
|
+
unassigned.flatten.delete_if { |task| assigned.find_index(task) }
|
391
398
|
end
|
392
399
|
|
393
400
|
public
|
@@ -396,16 +403,18 @@ module Syctask
|
|
396
403
|
def get_times
|
397
404
|
work_time = [@starts.h, @ends.round_up]
|
398
405
|
meeting_times = []
|
399
|
-
@meetings
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
406
|
+
if @meetings
|
407
|
+
@meetings.each do |meeting|
|
408
|
+
meeting_time = Array.new(2)
|
409
|
+
meeting_time[0] = hour_offset(@starts.h, meeting.starts.h) +
|
410
|
+
minute_offset(meeting.starts.m)
|
411
|
+
meeting_time[1] = hour_offset(@starts.h, meeting.ends.h) +
|
412
|
+
minute_offset(meeting.ends.m)
|
413
|
+
meeting_times << meeting_time
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
[work_time, meeting_times]
|
409
418
|
end
|
410
419
|
|
411
420
|
private
|
@@ -419,6 +428,5 @@ module Syctask
|
|
419
428
|
def minute_offset(minutes)
|
420
429
|
minutes.to_i.div(15)
|
421
430
|
end
|
422
|
-
|
423
431
|
end
|
424
432
|
end
|
data/lib/syctask/settings.rb
CHANGED
@@ -13,8 +13,9 @@ module Syctask
|
|
13
13
|
# system directory
|
14
14
|
def tasks(tasks)
|
15
15
|
service = Syctask::TaskService.new
|
16
|
-
if File.
|
17
|
-
general = YAML.
|
16
|
+
if File.exist? Syctask::DEFAULT_TASKS
|
17
|
+
general = YAML.safe_load_file(Syctask::DEFAULT_TASKS,
|
18
|
+
permitted_classes: [Syctask::Task, Symbol])
|
18
19
|
else
|
19
20
|
general = {}
|
20
21
|
end
|
@@ -30,9 +31,10 @@ module Syctask
|
|
30
31
|
# Retrieves the general purpose files from the default_tasks file in the
|
31
32
|
# syctask system directory
|
32
33
|
def read_tasks
|
33
|
-
if File.
|
34
|
+
if File.exist? Syctask::DEFAULT_TASKS and not \
|
34
35
|
File.read(Syctask::DEFAULT_TASKS).empty?
|
35
|
-
YAML.
|
36
|
+
YAML.safe_load_file(Syctask::DEFAULT_TASKS,
|
37
|
+
permitted_classes: [Syctask::Task, Symbol])
|
36
38
|
else
|
37
39
|
{}
|
38
40
|
end
|
data/lib/syctask/statistics.rb
CHANGED
@@ -19,6 +19,12 @@ module Syctask
|
|
19
19
|
|
20
20
|
# Creates a statistics report
|
21
21
|
def report(file, from="", to=from)
|
22
|
+
unless File.exist? file
|
23
|
+
return sprintf("Warning: Statistics log file %s",
|
24
|
+
file.bright).color(:red) +
|
25
|
+
sprintf(" is missing!\n%sNo statistics available!\n",
|
26
|
+
" "*9).color(:red)
|
27
|
+
end
|
22
28
|
|
23
29
|
from, to, time_log, count_log = logs(file, from, to)
|
24
30
|
working_days = time_log["work"].count.to_s if time_log["work"]
|