syc-task 0.0.2 → 0.0.3

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.
@@ -0,0 +1,23 @@
1
+ require_relative 'times.rb'
2
+
3
+ module Syctask
4
+
5
+ class Meeting
6
+
7
+ attr_accessor :starts
8
+ attr_accessor :ends
9
+ attr_accessor :title
10
+ attr_accessor :tasks
11
+
12
+ # Sets the busy time for the schedule. The busy times have to be provided
13
+ # as hh:mm-hh:mm. Optionally a title for the busy time can be provided
14
+ def initialize(time, title="", tasks=[])
15
+ @starts = Syctask::Times.new(time[0..1])
16
+ @ends = Syctask::Times.new(time[2..3])
17
+ @title = title
18
+ @tasks = tasks
19
+ end
20
+
21
+ end
22
+
23
+ end
@@ -0,0 +1,335 @@
1
+ require_relative 'times.rb'
2
+ require_relative 'meeting.rb'
3
+
4
+ module Syctask
5
+
6
+ # Schedule represents a working day with a start and end time, meeting times
7
+ # and titles and tasks. Tasks can also be associated to meetings as in an
8
+ # agenda.
9
+ # Invokation example
10
+ # work = ["8","30","18","45"]
11
+ # busy = [["9","0","10","0"],["11","30","12","15"]]
12
+ # titles = ["Ruby class room training","Discuss Ruby"]
13
+ # tasks = [task1,task2,task3,task4,task5,task6]
14
+ # schedule = Syctask::Schedule.new(work,busy,titles,tasks)
15
+ # schedule.graph.each {|output| puts output}
16
+ #
17
+ # This will create following output
18
+ # Meetings
19
+ # --------
20
+ # A - Ruby class room training
21
+ # B - Discuss Ruby
22
+ #
23
+ # A B
24
+ # xxoo/////xxx|-////oooooxoooo|---|---|---|---|
25
+ # 8 9 10 11 12 13 14 15 16 17 18 19
26
+ # 1 2 3 4 5
27
+ # 6
28
+ #
29
+ # Tasks
30
+ # -----
31
+ # 0 - 1: task1
32
+ # 1 - 2: task2
33
+ # 2 - 3: task3
34
+ # 3 - 4: task4
35
+ # 4 - 5: task5
36
+ # 5 - 6: task6
37
+ #
38
+ # Subsequent tasks are are displayed in the graph alternating with x and o.
39
+ # Meetings are indicated with / and the start is marked with A, B and so on.
40
+ # Task IDs are shown below the graph. The graph will be printed colored.
41
+ # Meetings in red, free times in green and tasks in blue. The past time is
42
+ # shown in black.
43
+ class Schedule
44
+ # Color of meetings
45
+ BUSY_COLOR = :red
46
+ # Color of free times
47
+ FREE_COLOR = :green
48
+ # Color of tasks
49
+ WORK_COLOR = :blue
50
+ # If tasks cannot be assigned to the working time this color is used
51
+ UNSCHEDULED_COLOR = :yellow
52
+ # Regex scans tasks and free times in the graph
53
+ GRAPH_PATTERN = /[\|-]+|\/+|[xo]+/
54
+ # Regex scans meetings in the graph
55
+ BUSY_PATTERN = /\/+/
56
+ # Regex scans free times in the graph
57
+ FREE_PATTERN = /[\|-]+/
58
+ # Regex scans tasks in the graph
59
+ WORK_PATTERN = /[xo]+/
60
+
61
+ # Start time of working day
62
+ attr_reader :starts
63
+ # End time of working day
64
+ attr_reader :ends
65
+ # Meetings assigned to the work time
66
+ attr_accessor :meetings
67
+ # Tasks assigned to the work time
68
+ attr_accessor :tasks
69
+
70
+ # Creates a new Schedule and initializes work time, busy times, titles and
71
+ # tasks. Work time is mandatory, busy times, titles and tasks are optional.
72
+ # Values have to be provided as
73
+ # * work time: [start_hour, start_minute, end_hour, end_minute]
74
+ # * busy time: [[start_hour, start_minute, end_hour, end_minute],[...]]
75
+ # * titles: [title,...]
76
+ # * tasks: [task,...]
77
+ def initialize(work_time, busy_time=[], titles=[], tasks=[])
78
+ @starts = Syctask::Times.new([work_time[0], work_time[1]])
79
+ @ends = Syctask::Times.new([work_time[2], work_time[3]])
80
+ @meetings = []
81
+ titles ||= []
82
+ busy_time.each.with_index do |busy,index|
83
+ title = titles[index] ? titles[index] : "Meeting #{index}"
84
+ @meetings << Syctask::Meeting.new(busy, title)
85
+ end
86
+ @tasks = tasks
87
+ end
88
+
89
+ # Sets the assignments containing tasks that are assigned to meetings.
90
+ # Returns true if succeeds
91
+ def assign(assignments)
92
+ assignments.each do |assignment|
93
+ number = assignment[0].upcase.ord - "A".ord
94
+ return false if number < 0 or number > @meetings.size
95
+ assignment[1].split(',').each do |index|
96
+ @meetings[number].tasks << @tasks[index.to_i] if @tasks[index.to_i]
97
+ end
98
+ @meetings[number].tasks.uniq!
99
+ end
100
+ true
101
+ end
102
+
103
+ # Creates a meeting list for printing. Returns the meeting list
104
+ def meeting_list
105
+ list = sprintf("%s", "Meetings\n").color(:red)
106
+ list << sprintf("%s", "--------\n").color(:red)
107
+ meeting_number = "A"
108
+ @meetings.each do |meeting|
109
+ list << sprintf("%s - %s\n", meeting_number, meeting.title).color(:red)
110
+ meeting_number.next!
111
+ meeting.tasks.each do |task|
112
+ task_color = task.done? ? :green : :blue
113
+ list << sprintf("%5s - %s\n", task.id, task.title).color(task_color)
114
+ end
115
+ end
116
+ list
117
+ end
118
+
119
+ # Creates a meeting caption and returns it for printing
120
+ def meeting_caption
121
+ work_time, meeting_times = get_times
122
+ caption = ""
123
+ meeting_number = "A"
124
+ meeting_times.each do |times|
125
+ caption << ' ' * (times[0] - caption.size) + meeting_number
126
+ meeting_number.next!
127
+ end
128
+ sprintf("%s", caption).color(:red)
129
+ end
130
+
131
+ # Creates the time caption for the time line
132
+ def time_caption
133
+ work_time = get_times[0]
134
+ caption = ""
135
+ work_time[0].upto(work_time[1]) do |time|
136
+ caption << time.to_s + (time < 9 ? ' ' * 3 : ' ' * 2)
137
+ end
138
+ sprintf("%s", caption)
139
+ end
140
+
141
+ # graph first creates creates the time line. Then the busy times are added.
142
+ # After that the tasks are added to the time line and the task caption and
143
+ # task list is created.
144
+ # graph returns the graph, task caption, task list and meeting list
145
+ # * time line
146
+ # * add meetings to time line
147
+ # * add tasks to time line
148
+ # * create task caption
149
+ # * create task list
150
+ # * create meeting caption
151
+ # * create meeting list
152
+ # * return time line, task caption, task list, meeting caption and meeting
153
+ # list
154
+ def graph
155
+ work_time, meeting_times = get_times
156
+ time_line = "|---" * (work_time[1]-work_time[0]) + "|"
157
+ meeting_times.each do |time|
158
+ time_line[time[0]..time[1]] = '/' * (time[1] - time[0]+1)
159
+ end
160
+
161
+ task_list, task_caption = assign_tasks_to_graph(time_line)
162
+
163
+ [meeting_list, meeting_caption,
164
+ colorize(time_line), time_caption,
165
+ task_caption, task_list]
166
+ end
167
+
168
+ private
169
+
170
+ # Colors the time line free time green, busy time red and tasks blue. The
171
+ # past time is colored black
172
+ def colorize(time_line)
173
+ time_line, future = split_time_line(time_line)
174
+ future.scan(GRAPH_PATTERN) do |part|
175
+ time_line << sprintf("%s", part).color(BUSY_COLOR) unless part.scan(BUSY_PATTERN).empty?
176
+ time_line << sprintf("%s", part).color(FREE_COLOR) unless part.scan(FREE_PATTERN).empty?
177
+ time_line << sprintf("%s", part).color(WORK_COLOR) unless part.scan(WORK_PATTERN).empty?
178
+ end if future
179
+ time_line
180
+ end
181
+
182
+ # Splits the time line at the current time. Returning the past part and the
183
+ # future part.
184
+ def split_time_line(time_line)
185
+ time = Time.now
186
+ offset = (time.hour - @starts.h) * 4 + time.min.div(15)
187
+ past = time_line.slice(0,offset)
188
+ future = time_line.slice(offset, time_line.size - offset)
189
+ [past, future]
190
+ end
191
+
192
+ # Assigns the tasks to the timeline in alternation x and o subsequent tasks.
193
+ # Returns the task list and the task caption
194
+ def assign_tasks_to_graph(time_line)
195
+ unscheduled_tasks = []
196
+ signs = ['x','o']
197
+ positions = {}
198
+ position = 0
199
+ unassigned_tasks.each.with_index do |task, index|
200
+ duration = task.duration.to_i
201
+ free_time = scan_free(time_line, duration, position)
202
+ position = free_time[0]
203
+ if position.nil?
204
+ unscheduled_tasks << task
205
+ next
206
+ end
207
+ time_line[position..(position + duration-1)] =
208
+ signs[index%2] * duration
209
+ positions[position] = task.id
210
+ end
211
+
212
+ max_id_size = 1
213
+ @tasks.each {|task| max_id_size = [task.id.to_s.size, max_id_size].max}
214
+ max_ord_size = (@tasks.size - 1).to_s.size
215
+
216
+ task_list = sprintf("%s", "Tasks\n").color(:blue)
217
+ task_list << sprintf("%s", "-----\n").color(:blue)
218
+ @tasks.each.with_index do |task, i|
219
+ if task.done?
220
+ color = :green
221
+ elsif unscheduled_tasks.find_index(task)
222
+ color = UNSCHEDULED_COLOR
223
+ else
224
+ color = WORK_COLOR
225
+ end
226
+ task_list << sprintf("%#{max_ord_size}d: %#{max_id_size}s - %s\n", i, task.id, task.title).
227
+ color(color)
228
+ end
229
+
230
+ task_caption = ""
231
+ create_caption(positions).each do |caption|
232
+ task_caption << sprintf("%s\n", caption).color(WORK_COLOR)
233
+ end
234
+
235
+ [task_list, task_caption]
236
+
237
+ end
238
+
239
+ # creates the caption of the graph with hours in 1 hour steps and task IDs
240
+ # that indicate where in the schedule a task is scheduled.
241
+ def create_caption(positions)
242
+ counter = 0
243
+ lines = [""]
244
+ positions.each do |position,id|
245
+ line_id = next_line(position,lines,counter)
246
+ legend = ' ' * [0, position - lines[line_id].size].max + id.to_s
247
+ lines[line_id] += legend
248
+ counter += 1
249
+ end
250
+ lines
251
+ end
252
+
253
+ # Creates a new line if the the task ID in the caption would override the
254
+ # task ID of a previous task. The effect is shown below
255
+ # |xx-|//o|x--|
256
+ # 8 9 10 10
257
+ # 10 101
258
+ # 11 2
259
+ # position is the position (time) within the schedule
260
+ # lines is the available ID lines (above we have 2 ID lines)
261
+ # counter is the currently displayed line. IDs are displayed alternating in
262
+ # each line, when we have 2 lines IDs will be printed in line 1,2,1,2...
263
+ def next_line(position, lines, counter)
264
+ line = lines[counter%lines.size]
265
+ return counter%lines.size if line.size == 0 or line.size < position - 1
266
+ lines.each.with_index do |line, index|
267
+ return index if line.size < position - 1
268
+ end
269
+ lines << ""
270
+ return lines.size - 1
271
+ end
272
+
273
+ # Scans the schedule for free time where a task can be added to. Count
274
+ # specifies the length of the free time and the position where to start
275
+ # scanning within the graph
276
+ def scan_free(graph, count, position)
277
+ pattern = /(?!\/)[\|-]{#{count}}(?<=-|\||\/)/
278
+
279
+ positions = []
280
+ index = position
281
+ while index and index < graph.size
282
+ index = graph.index(pattern, index)
283
+ if index
284
+ positions << index
285
+ index += 1
286
+ end
287
+ end
288
+ positions
289
+ end
290
+
291
+ # Returns the tasks that are not assigned to meetings
292
+ def unassigned_tasks
293
+ assigned = []
294
+ @meetings.each do |meeting|
295
+ assigned << meeting.tasks
296
+ end
297
+ assigned.flatten!
298
+
299
+ unassigned = []
300
+ unassigned << @tasks
301
+ unassigned.flatten.delete_if {|task| assigned.find_index(task)}
302
+ end
303
+
304
+ public
305
+
306
+ # Retrieves the work and busy times transformed to the time line scale
307
+ def get_times
308
+ work_time = [@starts.h, @ends.round_up]
309
+ meeting_times = []
310
+ @meetings.each do |meeting|
311
+ meeting_time = Array.new(2)
312
+ meeting_time[0] = hour_offset(@starts.h, meeting.starts.h) +
313
+ minute_offset(meeting.starts.m)
314
+ meeting_time[1] = hour_offset(@starts.h, meeting.ends.h) +
315
+ minute_offset(meeting.ends.m)
316
+ meeting_times << meeting_time
317
+ end if @meetings
318
+
319
+ times = [work_time, meeting_times]
320
+ end
321
+
322
+ private
323
+
324
+ # Transposes a time hour to a graph hour
325
+ def hour_offset(starts, ends)
326
+ (ends - starts) * 4
327
+ end
328
+
329
+ # Transposes a time minute to a graph minute
330
+ def minute_offset(minutes)
331
+ minutes.to_i.div(15)
332
+ end
333
+
334
+ end
335
+ end
@@ -0,0 +1,111 @@
1
+ require 'fileutils'
2
+ require_relative '../sycutil/console.rb'
3
+ require_relative 'task_service.rb'
4
+
5
+ module Syctask
6
+ PROMPT_STRING = '(a)dd, (c)omplete, (s)kip, (q)uit: '
7
+
8
+ class TaskPlanner
9
+ WORK_DIR = File.expand_path("~/.tasks")
10
+
11
+ def initialize
12
+ @console = Sycutil::Console.new
13
+ @service = TaskService.new
14
+ make_todo_today_file(Time.now.strftime("%Y-%m-%d"))
15
+ end
16
+
17
+ # List each task and prompt the user whether to add the task to the planned
18
+ # tasks. The user doesn't specify a duration for the task operation the
19
+ # duration will be set to 30 minutes which equals two time chunks. The
20
+ # count of planned tasks is returned
21
+ def plan_tasks(tasks, date=Time.now.strftime("%Y-%m-%d"))
22
+ already_planned = self.get_tasks(date)
23
+ count = 0
24
+ re_display = false
25
+ planned = []
26
+ tasks.each do |task|
27
+ next if already_planned.find_index {|t| t == task}
28
+ unless re_display
29
+ task.print_pretty
30
+ else
31
+ task.print_pretty(true)
32
+ re_display = false
33
+ end
34
+ choice = @console.prompt PROMPT_STRING
35
+ case choice
36
+ when 'a'
37
+ print "Duration (1 = 15 minutes, return 30 minutes): "
38
+ duration = gets.chomp
39
+ task.duration = duration.empty? ? 2 : duration
40
+ task.options[:follow_up] = date
41
+ @service.save(task.dir, task)
42
+ planned << task
43
+ count += 1
44
+ when 'c'
45
+ re_display = true
46
+ redo
47
+ when 's'
48
+ #do nothing
49
+ when 'q'
50
+ break
51
+ end
52
+ end
53
+ save_tasks(planned)
54
+ count
55
+ end
56
+
57
+ # Add the tasks to the planned tasks
58
+ def add_tasks(tasks)
59
+ save_tasks(tasks)
60
+ end
61
+
62
+ # Remove planned tasks from the task plan based on the provided filter
63
+ # (filter options see Task#matches?). Returns the count of removed tasks
64
+ def remove_tasks(date=Time.now.strftime("%Y-%m-%d"), filter={})
65
+ planned = []
66
+ tasks = self.get_tasks(date)
67
+ tasks.each do |task|
68
+ planned << task unless task.matches?(filter)
69
+ end
70
+ save_tasks(planned, true)
71
+ tasks.size - planned.size
72
+ end
73
+
74
+ # Get planned tasks of the specified date. Retrieve only tasks that match
75
+ # the specified filter (filter options see Task#matches?)
76
+ def get_tasks(date=Time.now.strftime("%Y-%m-%d"), filter={})
77
+ make_todo_today_file(date)
78
+ tasks = []
79
+ File.open(@todo_today_file, 'r') do |file|
80
+ file.each do |line|
81
+ dir, id = line.chomp.split(",")
82
+ task = @service.read(dir, id)
83
+ tasks << task if not task.nil? and task.matches?(filter)
84
+ end
85
+ end if File.exists? @todo_today_file
86
+ tasks
87
+ end
88
+
89
+ private
90
+
91
+ # Creates a file where the planned tasks are saved to
92
+ def make_todo_today_file(date)
93
+ file_name = Time.now.strftime("#{date}_planned_tasks")
94
+ @todo_today_file = WORK_DIR+"/"+file_name
95
+ end
96
+
97
+ # Save the tasks to a file. If override is true the file is overriden
98
+ # otherwise the tasks are appended
99
+ def save_tasks(tasks, override=false)
100
+ mode = override ? 'w' : 'a'
101
+ FileUtils.mkdir_p WORK_DIR unless File.exists? WORK_DIR
102
+ File.open(@todo_today_file, mode) do |file|
103
+ tasks.each do |task|
104
+ file.puts("#{task.dir},#{task.id}")
105
+ end
106
+ end
107
+ end
108
+
109
+ end
110
+
111
+ end
@@ -0,0 +1,172 @@
1
+ require_relative 'schedule.rb'
2
+
3
+ module Syctask
4
+
5
+ # The TaskScheduler creates a graphical representation of a working schedule
6
+ # with busy times visualized. A typical invokation would be
7
+ # work_time = "8:00-18:00"
8
+ # busy_time = "9:00-9:30,13:00-14:30"
9
+ # scheduler = Syctask::TaskScheduler.new(work_time, busy_time)
10
+ # scheduler.print_graph
11
+ # The output would be
12
+ # |---///-|---|---|---///////-|---|---|---|
13
+ # 8 9 10 11 12 13 14 15 16 17 18
14
+ # To add tasks to the schedule tasks have to provided (see Task). A task has
15
+ # a duration which indicates the time it is planned to process a task. The
16
+ # duration is an Integer 1,2,.. where 1 is 15 minutes and 2 is 30 minutes and
17
+ # so on. Assuming we have 5 tasks with a duration of 2, 5, 3, 2 and 3 15
18
+ # minute chunks. Then the invokation of
19
+ # scheduler.schedule_tasks(tasks)
20
+ # would output the schedule
21
+ # |xx-///ooooo|xxx|oo-///////xxx--|---|---|
22
+ # 8 9 10 11 12 13 14 15 16 17 18
23
+ # The tasks are added to the schedule dependent on the time chunks and the
24
+ # available free time gaps.
25
+ class TaskScheduler
26
+ # Time pattern that matches 24 hour times '12:30'
27
+ TIME_PATTERN = /(2[0-3]|[01]?[0-9]):([0-5]?[0-9])/
28
+
29
+ # Work time pattern scans time like '8:00-18:00'
30
+ WORK_TIME_PATTERN = /#{TIME_PATTERN}-#{TIME_PATTERN}/
31
+
32
+ # Busy time pattern scans times like '9:00-9:30,11:00-11:45'
33
+ BUSY_TIME_PATTERN =
34
+ /#{TIME_PATTERN}-#{TIME_PATTERN}(?=,)|#{TIME_PATTERN}-#{TIME_PATTERN}$/
35
+
36
+ # Scans assignments of tasks to meetings 'A:0,2,4;B:3,4,5'
37
+ ASSIGNMENT_PATTERN = /([a-zA-Z]):(\d+(?:,\d+|\d+;)*)/
38
+
39
+ # Working directory
40
+ WORK_DIR = File.expand_path("~/.tasks")
41
+
42
+ # Creates a new TaskScheduler.
43
+ def initialize
44
+ @work_time = []
45
+ @busy_time = []
46
+ @meetings = []
47
+ @tasks = []
48
+ end
49
+
50
+ # Set the work time. Raises an exception if begin time is after start time
51
+ # Invokation: set_work_time(["8","0","18","30"])
52
+ def set_work_time(work_time)
53
+ @work_time = process_work_time(work_time)
54
+ unless sequential?(@work_time)
55
+ raise Exception, "Begin time has to be before end time"
56
+ end
57
+ end
58
+
59
+ # Set the busy times. Raises an exception if one begin time is after start
60
+ # time
61
+ # Invokation: set_busy_times([["9","30","10","45"],["12","0","13","45"]])
62
+ def set_busy_times(busy_time)
63
+ @busy_time = process_busy_time(busy_time)
64
+ @busy_time.each do |busy|
65
+ unless sequential?(busy)
66
+ raise Exception, "Begin time has to be before end time"
67
+ end
68
+ end
69
+ end
70
+
71
+ # Sets the titles of the meetings (busy times)
72
+ # Invokation: set_meeting_titles("title1,title2,title3")
73
+ def set_meeting_titles(titles)
74
+ @meetings = titles.split(",") if titles
75
+ end
76
+
77
+ def set_tasks(tasks)
78
+ @tasks = tasks
79
+ end
80
+
81
+ # Add scheduled tasks to busy times
82
+ # Invokation: set_task_assignments([["A","1,2,3"],["B","2,5,6,7"]])
83
+ def set_task_assignments(assignments)
84
+ @assignments = assignments.scan(ASSIGNMENT_PATTERN)
85
+ raise "No valid assignment" if @assignments.empty?
86
+ end
87
+
88
+ private
89
+
90
+ # Checks the sequence of begin and end time. Returns true if begin is before
91
+ # end time otherwise false
92
+ def sequential?(range)
93
+ return true if range[0].to_i < range[2].to_i
94
+ if range[0].to_i == range[2].to_i
95
+ return true if range[1].to_i < range[3].to_i
96
+ end
97
+ false
98
+ end
99
+
100
+ # Scans the work time and separates hours and minutes. Raises an Exception
101
+ # if work time is nil or empty
102
+ def process_work_time(work_time)
103
+ raise Exception, "Work time must not be nil" if work_time.nil?
104
+ time = work_time.scan(WORK_TIME_PATTERN).flatten
105
+ raise Exception, "Work time cannot be empty" if time.empty?
106
+ time
107
+ end
108
+
109
+ # Scans the busy times and separates hours and minutes.
110
+ def process_busy_time(busy_time)
111
+ busy_time = "" if busy_time.nil?
112
+ busy_time.scan(BUSY_TIME_PATTERN).each {|busy| busy.compact!}
113
+ end
114
+
115
+ public
116
+
117
+ # Restores the value of a previous invokation. Posible values are
118
+ # :work_time, :busy_time, :meetings and :assignments
119
+ # Returns true if a value from a previous call is available otherwise false
120
+ def restore(value)
121
+ work_time, busy_time, meetings, assignments = restore_state
122
+ @work_time = work_time if value == :work_time
123
+ @busy_time = busy_time if value == :busy_time
124
+ @meetings = meetings if value == :meetings
125
+ @assignments = assignments if value == :assignments
126
+ return false if value == :work_time and (@work_time.nil? or @work_time.empty?)
127
+ return false if value == :busy_time and (@busy_time.nil? or @busy_time.empty?)
128
+ return false if value == :meetings and (@busy_time.nil? or @meetings.empty?)
129
+ return false if value == :assignments and (@assignments.nil? or @assignments.empty?)
130
+ true
131
+ end
132
+
133
+ # Prints the meeting list, timeline and task list
134
+ def show
135
+ schedule = Syctask::Schedule.new(@work_time, @busy_time, @meetings, @tasks)
136
+ schedule.assign(@assignments) if @assignments
137
+ schedule.graph.each {|output| puts output}
138
+ save_state @work_time, @busy_time, @meetings, @assignments
139
+ true
140
+ end
141
+
142
+ private
143
+
144
+ # Saves the work time, busy time, meetings and assignments from the
145
+ # invokation for later retrieval
146
+ def save_state(work_time, busy_time, meetings, assignments)
147
+ state = {work_time: work_time,
148
+ busy_time: busy_time,
149
+ meetings: meetings,
150
+ assignments: assignments}
151
+ FileUtils.mkdir WORK_DIR unless File.exists? WORK_DIR
152
+ state_file = WORK_DIR+'/'+Time.now.strftime("%Y-%m-%d_time_schedule")
153
+ File.open(state_file, 'w') do |file|
154
+ YAML.dump(state, file)
155
+ end
156
+ end
157
+
158
+ # Retrieves the state of the last invokation. Returns the work and busy
159
+ # time, meetings and assignments
160
+ def restore_state
161
+ state_file = WORK_DIR+'/'+Time.now.strftime("%Y-%m-%d_time_schedule")
162
+ return [[], [], [], []] unless File.exists? state_file
163
+ state = YAML.load_file(state_file)
164
+ [state[:work_time],
165
+ state[:busy_time],
166
+ state[:meetings],
167
+ state[:assignments]]
168
+ end
169
+
170
+ end
171
+
172
+ end
@@ -0,0 +1,19 @@
1
+ module Syctask
2
+
3
+ class Times
4
+
5
+ attr_reader :h
6
+ attr_reader :m
7
+
8
+ def initialize(time)
9
+ @h = time[0].to_i
10
+ @m = time[1].to_i
11
+ end
12
+
13
+ def round_up
14
+ @m > 0 ? @h+1 : @h
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -1,5 +1,5 @@
1
1
  # Syctask provides functions for managing tasks in a task list
2
2
  module Syctask
3
3
  #Holds the version number of syctask
4
- VERSION = '0.0.2'
4
+ VERSION = '0.0.3'
5
5
  end
data/lib/syctask.rb CHANGED
@@ -4,6 +4,8 @@ require 'syctask/task.rb'
4
4
  require 'syctask/task_service.rb'
5
5
  require 'syctask/task_scheduler.rb'
6
6
  require 'syctask/task_planner.rb'
7
+ require 'syctask/schedule.rb'
8
+ require 'sycutil/console.rb'
7
9
 
8
10
  # Add requires for other files you add to your project here, so
9
11
  # you just need to require this one file in your bin file
@@ -0,0 +1,60 @@
1
+ require 'io/wait'
2
+
3
+ # Module Inspector contains functions related to the Console that is helpers
4
+ # for user input
5
+ module Sycutil
6
+
7
+ # Console provides functions for user input
8
+ class Console
9
+
10
+ # Listens on Ctrl-C and exits the application
11
+ Signal.trap("INT") do
12
+ puts "-> program terminated by user"
13
+ exit
14
+ end
15
+
16
+ # Listens for key presses and returns the pressed key without pressing
17
+ # return
18
+ #
19
+ # :call-seq:
20
+ # char_if_pressed
21
+ def char_if_pressed
22
+ begin
23
+ system("stty raw -echo")
24
+ c = nil
25
+ if $stdin.ready?
26
+ c = $stdin.getc
27
+ end
28
+ c.chr if c
29
+ ensure
30
+ system "stty -raw echo"
31
+ end
32
+ end
33
+
34
+ # Prompts the user for input.
35
+ #
36
+ # :call-seq:
37
+ # prompt(choice_line) -> char
38
+ #
39
+ # choice_line is the prompt string. If the prompt string contains a (x)
40
+ # sequence x is a valid choice the is relized when pressed and returned.
41
+ def prompt(choice_line)
42
+ pattern = /(?<=\()./
43
+ choices = choice_line.scan(pattern)
44
+
45
+ choice = nil
46
+
47
+ while choices.find_index(choice).nil?
48
+ print choice_line
49
+ choice = nil
50
+ choice = char_if_pressed while choice == nil
51
+ sleep 0.1
52
+ puts
53
+ end
54
+
55
+ choice
56
+ end
57
+
58
+ end
59
+
60
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: syc-task
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-10 00:00:00.000000000 Z
12
+ date: 2013-03-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -154,8 +154,14 @@ files:
154
154
  - lib/syctask/version.rb
155
155
  - lib/syctask/task.rb
156
156
  - lib/syctask/task_service.rb
157
+ - lib/syctask/task_planner.rb
157
158
  - lib/syctask/evaluator.rb
158
159
  - lib/syctask.rb
160
+ - lib/syctask/task_scheduler.rb
161
+ - lib/syctask/meeting.rb
162
+ - lib/syctask/times.rb
163
+ - lib/syctask/schedule.rb
164
+ - lib/sycutil/console.rb
159
165
  - README.rdoc
160
166
  - syctask.rdoc
161
167
  homepage: http://syc.dyndns.org/drupal/syc-task