Skip to content

Instantly share code, notes, and snippets.

@damien
Created December 18, 2014 17:20
Show Gist options
  • Save damien/0f3ff26ba9dd06306a8a to your computer and use it in GitHub Desktop.
Save damien/0f3ff26ba9dd06306a8a to your computer and use it in GitHub Desktop.
Course code parser
# A parser for course code strings
#
# Course codes are unique identifiers used to identify particular classes instructed at an edicuational institution.
#
# There isn't any real standard for course codes, but the examples below demonstrate common formats for course codes
# in the places where this parser is used.
#
# The parser itself is generated using [Treetop](https://github.com/nathansobo/treetop), so look there if you're interested
# in the underlying framework that generates the CourseCodeParser class when we load up our parser grammar.
#
# Course Code format
# ------------------
# FINN 936 1 # Standard format, department code, followed by course number
# # and section number
# GRN 900P SE # CPT format, department code followed by a course number,
# # followed by a 'F' or 'P' (full-time, part-time), followed
# # by an 2+ character suffix indicating the department running
# # that particular CPT section/courseterm
# GRN 900F SE 1 # Identical to the above, with the addition
# # of a section number
#
# @example Parsing a course code in the standard course code format
# cc = CourseCodeParser.new.parse('CEN 948 1')
# cc.course_code.text_value # => 'CEN 948'
# cc.course_code.department_code.text_value # => 'CEN'
# cc.course_code.course_number.text_value # => '948'
# cc.section_number.text_value # => '1'
#
# @example Parsing a course code in the CPT format
# cc = CourseCodeParser.new.parse('GRN 900F CE')
# cc.course_code.text_value # => 'GRN 900F'
# cc.course_code.department_code.text_value # => 'GRN'
# cc.course_code.course_number.text_value # => '900F'
# cc.cpt_division.text_value # => 'CE'
#
# @note This class is generated by the Treetop grammer file defined in
# `course_code.treetop`
class CourseCodeParser; end
# The above line is a bit of a hack to let us get generated documentation for
# the dynamically defined class CourseCodeParser. To keep that hack from
# from breaking real, useful code, we undefine it here.
Object.send(:remove_const, :CourseCodeParser)
Treetop.load 'course_code.treetop'
grammar CourseCode
rule root
(course_code space section_number / course_code space cpt_division space section_number / course_code space cpt_division) {
# For our purposes, the 'section' identifier of a course code may be
# a section_number, a cpt_division, or a combination of the two.
def section
if respond_to?(:cpt_division) && respond_to?(:section_number)
format('%s %s', cpt_division.text_value, section_number.text_value)
elsif respond_to?(:cpt_division)
cpt_division.text_value
elsif respond_to?(:section_number)
section_number.text_value
end
end
}
end
rule section_number
number 1..2
end
rule course_code
department_code space course_number
end
rule cpt_division
letter letter
end
rule course_number
number 2..3 letter?
end
rule department_code
letter 2..4
end
rule number
[0-9]
end
rule letter
[a-zA-Z]
end
rule space
("\\\n" / [ \t])*
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment