Browse files

SR::EditFile::Parser

* Implemented and tested.
* Lesson#parse(string) added to ease implementation.
  * Also Lesson#== and Lesson#hash
* Parser emits value objects DayVO and LessonVO.
  * parse(str) -> [DayVO] where DayVO contains schoolday and [LessonVO]
  • Loading branch information...
1 parent 574d9b8 commit dd4fd36ba0ed6c33a2729b85c946157d1ccc2c93 @gsinclair committed Mar 11, 2012
View
54 doc/devel-log/2012-03-03-describing-a-whole-days-lessons.markdown
@@ -201,3 +201,57 @@ Implemented and tested.
end
end
+## Iteration 2: EditFile::Parser
+
+**(11 MAR 2012)**
+
+This took a patchy effort over a large number of days, but now it's done. There
+could be some issues in that I parse "\n\n" as "<PARA>", but we'll see.
+
+As the following code shows, the output of #parse is an array of DayVO objects,
+each of which tells the "schoolday" and an array of LessonVO objects (lesson +
+description). It's a sound representation of the data in the input string, which
+can be traversed for putting into the database.
+
+ D "EditFile::Parser" do
+ D.< {
+ @db = SR::Database.test
+ @parser = SR::EditFile::Parser.new(@db)
+ }
+ D "#parse" do
+ data = @parser.parse(input_string)
+ Ko data, Array
+ Eq data.size, 2
+ day = data.shift
+ Ko day, SR::EditFile::DayVO
+ Eq day.schoolday, @db.schoolday("Sem1 Tue 17A")
+ Eq day.lessons.size, 1
+ Eq day.lessons[0].lesson, SR::DO::Lesson.new('11',4)
+ Eq day.lessons[0].description, \
+ "Tax scales; finding tax payable for a given taxable income from a table. Discussion " \
+ "of gradients when the table information is drawn. <PARA> ex:(5C Q2-4esq)"
+ day = data.shift
+ Ko day, SR::EditFile::DayVO
+ Eq day.lessons.size, 3
+ Eq day.lessons[0].lesson, SR::DO::Lesson.new('11',1)
+ Eq day.lessons[0].description, \
+ "More work on the graphical aspects of tax tables. Tax deductions."
+ Eq day.lessons[1].lesson, SR::DO::Lesson.new('12',2)
+ Eq day.lessons[1].description, \
+ "Radian measure. Ruler demonstration. Examples converting between " \
+ "radians and degrees."
+ Eq day.lessons[2].lesson, SR::DO::Lesson.new('10',5)
+ Eq day.lessons[2].description, \
+ "Working lesson."
+ end
+ end
+
+Time for a commit.
+
+ SR::EditFile::Parser
+
+ * Implemented and tested.
+ * Lesson#parse(string) added to ease implementation.
+ * Also Lesson#== and Lesson#hash
+ * Parser emits value objects DayVO and LessonVO.
+ * parse(str) -> [DayVO] where DayVO contains schoolday and [LessonVO]
View
16 lib/school_record/domain_objects.rb
@@ -250,6 +250,22 @@ def to_s(format=:full)
end
end
def inspect() to_s end
+ # str: 10(3)
+ def Lesson.parse(str)
+ if str.strip[/^(\w+)\((\d)\)$/]
+ class_label, period = $1, $2.to_i
+ Lesson.new(class_label, period)
+ else
+ sr_int "Can't parse Lesson string: #{str}"
+ end
+ end
+ def ==(other)
+ [self.class, @class_label, @period] ==
+ [other.class, other.class_label, other.period]
+ end
+ def hash
+ [self.class, @class_label, @period].hash
+ end
end # class Lesson
# --------------------------------------------------------------------------- #
View
126 lib/school_record/edit_file/parser.rb
@@ -0,0 +1,126 @@
+
+module SR::EditFile
+ # This associates a schoolday with an array of LessonVO objects. A single
+ # DayVO therefore contains a user's input of lesson descriptions for one whole
+ # day.
+ class DayVO
+ attr_reader :schoolday, :lessons
+ def initialize(schoolday)
+ @schoolday, @lessons = schoolday, []
+ end
+ def add_lesson(lesson, description)
+ @lessons << LessonVO.new(lesson, description)
+ debug " DayVO[#{@schoolday.sem_date}] added lesson '#{description[0..10]}...'"
+ end
+ end
+
+ # This simply bundles a lesson (class and period) with a description for the
+ # sake of parsing the user's input.
+ class LessonVO
+ attr_reader :lesson, :description
+ def initialize(lesson, description)
+ @lesson, @description = lesson, description
+ end
+ end
+
+ # Takes the user's input (a long string) and returns an array of DayVO via
+ # the #parse method. This ignores comments.
+ #
+ # SR::EditFile::Parser.new(db).parse(string)
+ # -> DayVO[Thu 3A]
+ # LessonVO[10(0), "Function notation"]
+ # LessonVO[10(1), "Revised for test tomorrow"]
+ # LessonVO[7(2), "Number patterns..."]
+ # DayVO[Fri 3A]
+ # LessonVO[12(3), "Logs and exponentials introduction"]
+ # ...
+ # ...
+ #
+ # Paragraphs in the lesson descriptions are marked by <PARA>, which tends to
+ # be surrounded by a space. Code that wants to display these descriptions will
+ # want to do something like:
+ #
+ # description = description.gsub /\s*<PARA>\s*/, "\n\n"
+ #
+ # The destination for these descriptions is the database, anyway. It's
+ # probably good to leave the PARA codes in there.
+ class Parser
+ def initialize(db)
+ @db = db
+ end
+ def parse(string)
+ days = []
+ lines = string.split("\n")
+ lines.shift if lines.first =~ /^Edit: /
+ current_day = current_lesson = description = nil
+ loop do
+ line = lines.shift
+ break if line.nil?
+ trace :line, binding
+ case line.strip
+ when ""
+ debug " parse: empty line"
+ when /^#/
+ debug " parse: comment"
+ when /^~ Sem/
+ debug " parse: new day"
+ current_day = DayVO.new(parse_day(line))
+ days << current_day
+ when /^~ \w{1,7}\(\d\) \w\w\w$/
+ current_lesson = SR::DO::Lesson.parse(line.split[1])
+ debug " parse: new lesson -- #{current_lesson}"
+ description = extract_description(lines)
+ debug " extracted description: #{description[0..30]}..."
+ current_day.add_lesson(current_lesson, description)
+ end
+ end
+ days
+ end # parse
+
+ private
+ def parse_day(line)
+ if line[/~ (Sem\d \w+ \w+) ===*/]
+ @db.schoolday($1)
+ else
+ sr_int "Invalid line: #{line}"
+ end
+ end
+ def parse_lesson(line)
+ if line[/^~ (\S+) \w\w\w/]
+ SR::DO::Lesson.parse($1)
+ else
+ sr_int "Invalid line: #{line}"
+ end
+ end
+ def extract_description(lines)
+ # Read lines until we get to a directive or the end. Ignore comments.
+ #debug "SR::EditFile::Parser#extract_description"
+ #debug " - lines = #{lines.inspect}"
+ desc_lines = []
+ loop do
+ if lines.empty? or lines.first =~ /^~ /
+ break
+ else
+ line = lines.shift
+ next if line =~ /^#/
+ desc_lines << line.strip
+ end
+ end
+ #debug " - desc_lines == #{desc_lines.inspect}"
+ # Return a string where paragraph breaks are marked with <PARA> and there
+ # are no newlines.
+ words = []
+ desc_lines.each do |line|
+ if line.empty?
+ words << "<PARA>"
+ else
+ words << line.split
+ end
+ end
+ words = words.flatten.join(' ')
+ #debug " - words == #{words.inspect}"
+ words = words.gsub /(\s*<PARA>\s*)+$/, ""
+ words.strip
+ end
+ end # class Parser
+end # module SR::EditFile
View
77 test/edit_file/parser.rb
@@ -0,0 +1,77 @@
+def input_string
+ str = %{
+ +Edit: Sem1 Tue 17A, Sem1 Wed 17A
+ +
+ +~ Sem1 Tue 17A ========================================================
+ +
+ +# 10(2) [Moderator's assembly]
+ +
+ +# 12(3) Tue
+ +# Velocity and acceleration [this text there already; we don't process it]
+ +
+ +~ 11(4) Tue
+ +Tax scales; finding tax payable for a given taxable income from a
+ +table. Discussion of gradients when the table information is drawn.
+ +
+ +ex:(5C Q2-4esq)
+ +
+ +# 7(5) [Moderator's assembly]
+ +
+ +~ Sem1 Wed 17A ========================================================
+ +
+ +~ 11(1) Wed
+ +More work on the graphical aspects of tax tables. Tax deductions.
+ +
+ +~ 12(2) Wed
+ +Radian measure. Ruler demonstration. Examples converting between
+ +radians and degrees.
+ +
+ +# 7(4) Wed
+ +# Area of a triangle. Started with counting squares, then moved to general
+ +# diagrams, then to the formula.
+ +#
+ +# Several students had trouble with the algebraic letters used in the
+ +# formula, but they were OK with the general idea.
+ +#
+ +# ex:(7-04 Q1 Q3esq,q+a Q4ans)
+ +
+ +~ 10(5) Wed
+ +Working lesson.
+ +
+ +#vim: ft=school_record
+ }.margin
+end
+
+D "EditFile::Parser" do
+ D.< {
+ @db = SR::Database.test
+ @parser = SR::EditFile::Parser.new(@db)
+ }
+ D "#parse" do
+ data = @parser.parse(input_string)
+ Ko data, Array
+ Eq data.size, 2
+ day = data.shift
+ Ko day, SR::EditFile::DayVO
+ Eq day.schoolday, @db.schoolday("Sem1 Tue 17A")
+ Eq day.lessons.size, 1
+ Eq day.lessons[0].lesson, SR::DO::Lesson.new('11',4)
+ Eq day.lessons[0].description, \
+ "Tax scales; finding tax payable for a given taxable income from a table. Discussion " \
+ "of gradients when the table information is drawn. <PARA> ex:(5C Q2-4esq)"
+ day = data.shift
+ Ko day, SR::EditFile::DayVO
+ Eq day.lessons.size, 3
+ Eq day.lessons[0].lesson, SR::DO::Lesson.new('11',1)
+ Eq day.lessons[0].description, \
+ "More work on the graphical aspects of tax tables. Tax deductions."
+ Eq day.lessons[1].lesson, SR::DO::Lesson.new('12',2)
+ Eq day.lessons[1].description, \
+ "Radian measure. Ruler demonstration. Examples converting between " \
+ "radians and degrees."
+ Eq day.lessons[2].lesson, SR::DO::Lesson.new('10',5)
+ Eq day.lessons[2].description, \
+ "Working lesson."
+ end
+end
+

0 comments on commit dd4fd36

Please sign in to comment.