Jeff Schwab
7/2/2006 8:49:00 PM
Bucco wrote:
> I am trying to put together a simple script that will parse a text file
> that contains a list of tasks. Each line could be different in format
> from the other. Most lines have words that are marked and can be
> pulled out with a regex. Here is a simple example:
>
> (A) @home Mow lawn d:6/30/06
> @phone call home
> (B) p:program @pc @desk Add text parser to the program
>
> Basically, each line is a task in a list of todos. They can have one
> of three priority rankings (A), (B), or (C). The priority is always
> first on the line if it is present. Then There can be a project name
> that the task is related to, "p:program". The next item on the line is
> a context and starts with the @ symbol. Each task can have more than
> one context. After this is the task description that consists of one
> or more words and has no definitive marker. Some tasks may have a due
> date after the task that is marked by a d: followed by a date.
>
> So basically, the program will read in the text file, process each line
> so that a task is printed to a new file in either a prject file, due
> file, and/or context file. When processing each line, I thought of
> breaking them down by white space into an array and then using a regex
> to match the easy items and remove them the array and use them as a
> hash key for the task.
>
> I gues the best way might be to extract each marker assin it to a hash
> as a key and then extract the task and assign it to the hash as the
> value. I can't seem to get to this point without a lot of if
> statements. I was wondering if anyone else had a cleaner way of doing
> this.
Maybe something like this.
Unless you're dealing with a tremendous number of tasks, I'd skip all
those hashes. Just keep the tasks in a single array or hash and do
linear searches as necessary. There's an example at the bottom of this
code.
Beware that format errors will never actually be detected, because the
file format is so lenient. Given a line like this, The whole line is
assumed to be a task description:
(B p:program @pc @desk Add text parser to the program
class TaskFormatError < StandardError
end
class Task
attr :priority, true
attr :project, true
attr :context, true
attr :description, true
attr :due_date, true
# Initialize a task based on one line of a task file. Each line
# should have the following format, such that each item can be
# matched by the given regex. Items should be separated by
# white-space.
#
# 1. Optional priority as first item on line: /\(([ABC]))/
# 2. Optional project name: /p:(\S*)/
# 3. Optional context: /@(\S*)/
# 4. Task description: /.*/
# 5. Optional due date: /d:(\S*)/
def initialize(line)
raise TaskFormatError unless line =~
/(?:\(([ABC])\))?\s* # priority
(?:p:(\S*))?\s* # project
(?:@(\S*))?\s* # context
(.*) # description + trailing whitespace
(?:d:(\S*))?/x # due date
@priority = $1
@project = $2
@context = $3
@description = $4
@due_date = $5
# Remove trailing whitespace from description.
@description.gsub(/\s+$/, '')
end
# Return a one-line string summarizing this task. The string line
# can be read later by Task#initialize(line).
def to_s
s = ''
s << "(#{@priority}) " if @priority
s << "p:#{@project} " if @project
s << "@#{@context} " if @context
s << description
s << " d:#{@due_date}" if @due_date
s
end
end
tasks = []
ARGF.each do |line|
next if line =~ /^\s*$|^#/ # Skip blank lines and comments.
tasks << Task.new(line)
end
tasks.each do |task|
puts task.to_s if task.context.eql?('home')
end