J
James B Crigler
I need to read a file into memory and parse it for information on
demand as a kind of ad hoc query mechanism. (The file is
a non-tabular report from a database.)
Though there are other field types, for the time being, I only
want to consider fields that appear with a tag on a single line,
e.g.,
Title: A Tale Of Two Cities
Author: Charles Dickens
There are various classes of files representing different object
types as reported from the database. The tags, even for fields
like title and author, are not consistent among report types. (I
don't have control of the database, so I can't fix it.)
My original implementation approximated the code you'll find below.
There are some annoyances in the code:
1. The deferred lookups have to be written individually (def
title, def author, etc.), though they only have to be written
once if they belong in the base class.
2. I pass the variable into find_tagged_one_line to see whether
it already has a value, but I can't assign it there.
Is there a way, e.g., with missing_method, to create
a table-driven caching dispatch on the field names that performs
assignment in the find_... method?
class Literature
Tags = {
'title' => %r[^Title:\s*],
'author' => %r[^Author:\s*],
# etc
}
def initialize(path)
@text = Array.new
@tags = Tags
@title = nil
@author = nil
if File.exists? path
File.open(path).each do |line|
@text.push line.chomp
end
# else
# raise NoSuchLiterature
end
end
def find_tagged_one_line(re, var)
return var unless var.nil? # Got a value? Return it
m = nil
line = @text.find { |l| m = re.match(l) } # Match RE in array of lines
return "" if line.nil? # No match?
return line[m.end(0) .. -1] # Return part of line after tag
end
def title
@title = find_tagged_one_line(@tags['title'], @title)
end
def author
@author = find_tagged_one_line(@tags['author'], @author)
end
# etc
end
class Novel < Literature
Tags = {
'title' => %r[^Novel Title:\s*],
'author' => %r[^Novel Author:\s*],
'year' => %r[^Year of publication:\s*],
# etc
}
def initialize(path)
super(path)
@year = nil
@tags = Tags # Override the tags hash
end
def year
@year = find_tagged_one_line(@tags['year'], @year)
end
end
--
James B Crigler Voice: (770)494-2077
C-27J Software Requirements Manager Fax: (770)494-3886
Lockheed Martin Aeronautics Company
D/6B3M Z/0100
86 South Cobb Drive
Marietta GA 30063
"I say, Jerry! You'd be in a Blazing bad way if recalling to life
was to become the fashion, Jerry!" -- A Tale of Two Cities
demand as a kind of ad hoc query mechanism. (The file is
a non-tabular report from a database.)
Though there are other field types, for the time being, I only
want to consider fields that appear with a tag on a single line,
e.g.,
Title: A Tale Of Two Cities
Author: Charles Dickens
There are various classes of files representing different object
types as reported from the database. The tags, even for fields
like title and author, are not consistent among report types. (I
don't have control of the database, so I can't fix it.)
My original implementation approximated the code you'll find below.
There are some annoyances in the code:
1. The deferred lookups have to be written individually (def
title, def author, etc.), though they only have to be written
once if they belong in the base class.
2. I pass the variable into find_tagged_one_line to see whether
it already has a value, but I can't assign it there.
Is there a way, e.g., with missing_method, to create
a table-driven caching dispatch on the field names that performs
assignment in the find_... method?
class Literature
Tags = {
'title' => %r[^Title:\s*],
'author' => %r[^Author:\s*],
# etc
}
def initialize(path)
@text = Array.new
@tags = Tags
@title = nil
@author = nil
if File.exists? path
File.open(path).each do |line|
@text.push line.chomp
end
# else
# raise NoSuchLiterature
end
end
def find_tagged_one_line(re, var)
return var unless var.nil? # Got a value? Return it
m = nil
line = @text.find { |l| m = re.match(l) } # Match RE in array of lines
return "" if line.nil? # No match?
return line[m.end(0) .. -1] # Return part of line after tag
end
def title
@title = find_tagged_one_line(@tags['title'], @title)
end
def author
@author = find_tagged_one_line(@tags['author'], @author)
end
# etc
end
class Novel < Literature
Tags = {
'title' => %r[^Novel Title:\s*],
'author' => %r[^Novel Author:\s*],
'year' => %r[^Year of publication:\s*],
# etc
}
def initialize(path)
super(path)
@year = nil
@tags = Tags # Override the tags hash
end
def year
@year = find_tagged_one_line(@tags['year'], @year)
end
end
--
James B Crigler Voice: (770)494-2077
C-27J Software Requirements Manager Fax: (770)494-3886
Lockheed Martin Aeronautics Company
D/6B3M Z/0100
86 South Cobb Drive
Marietta GA 30063
"I say, Jerry! You'd be in a Blazing bad way if recalling to life
was to become the fashion, Jerry!" -- A Tale of Two Cities