summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSophie Forrest <git@sophieforrest.com>2024-09-12 02:31:27 +1200
committerSophie Forrest <git@sophieforrest.com>2024-09-12 02:31:27 +1200
commit14a8735623c7383c1ba5eb4fad13a5588beffabb (patch)
tree8d9a7b6811df58d9e65ce295c7e87b292f39ffd9
parent2acec90f5c1576e3fbceff218f781225ee6efdb7 (diff)
feat(parser): complete offering parser + courseid
Complete courseid and offering parsers. These will be swapped into the codebase in the next commit.
-rw-r--r--src/parser.rs105
1 files changed, 101 insertions, 4 deletions
diff --git a/src/parser.rs b/src/parser.rs
index c722bfc..87da6be 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -3,13 +3,16 @@
//! Nom parsers used within the parsing steps.
use nom::{
- bytes::complete::{tag, take_while},
- character::complete::multispace0,
- combinator::map_res,
- sequence::{pair, preceded},
+ branch::alt,
+ bytes::complete::{tag, take, take_till, take_while},
+ character::complete::{char, multispace0},
+ combinator::{map_res, rest},
+ sequence::{delimited, pair, preceded, separated_pair},
IResult,
};
+use crate::{CourseOffering, Trimester};
+
/// Determines if the provided character is an ascii digit.
const fn is_decimal_digit(c: char) -> bool {
c.is_ascii_digit()
@@ -42,6 +45,62 @@ pub fn course_reference_number(input: &str) -> IResult<&str, u16> {
preceded(pair(tag("CRN"), multispace0), crn_digits)(input)
}
+/// Parser that parses a timetable separator.
+///
+/// # Errors
+///
+/// This function will return an error if input does not match expected format by nom.
+pub fn timetable_separator(input: &str) -> IResult<&str, char> {
+ delimited(multispace0, char('\u{2022}'), multispace0)(input)
+}
+
+/// Parses a trimester from an input.
+///
+/// # Errors
+///
+/// This function will return an error if input does not match expected format by nom.
+pub fn trimester(input: &str) -> IResult<&str, Trimester> {
+ map_res(
+ alt((
+ tag("block dates/3"),
+ tag("part year/3"),
+ tag("full year"),
+ take_till(char::is_whitespace),
+ )),
+ Trimester::try_from,
+ )(input)
+}
+
+/// Parses a course offering from an input.
+///
+/// # Errors
+///
+/// This function will return an error if .
+pub fn offering(input: &str) -> IResult<&str, CourseOffering> {
+ let (input, (trimester, crn)) =
+ separated_pair(trimester, timetable_separator, course_reference_number)(input)?;
+ Ok((input, CourseOffering::new(crn, trimester)))
+}
+
+/// Parses a course title from an input.
+///
+/// # Errors
+///
+/// This function will return an error if nom is unable to parse the input. This should only happen
+/// if the input is less than 8 characters.
+pub fn title(input: &str) -> IResult<&str, &str> {
+ take(8usize)(input)
+}
+
+/// Parses a course subtitle from an input.
+///
+/// # Errors
+///
+/// This function will return an error if the subtitle is not preceded by "`\u{2013}` ".
+pub fn subtitle(input: &str) -> IResult<&str, &str> {
+ preceded(tag("\u{2013} "), rest)(input)
+}
+
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
@@ -71,4 +130,42 @@ mod tests {
fn crn_parser_no_whitespace() {
assert_eq!(course_reference_number("CRN615").unwrap().1, 615);
}
+
+ #[test]
+ fn offering_parser_alphabetic_durations() {
+ let block_dates = offering("block dates/3 \u{2022} CRN 25341").unwrap();
+
+ assert_eq!(block_dates.1.course_reference_number, 25341);
+ assert_eq!(block_dates.1.trimester, Trimester::BlockDates);
+
+ let part_year = offering("part year/3 \u{2022} CRN 1816").unwrap();
+
+ assert_eq!(part_year.1.course_reference_number, 1816);
+ assert_eq!(part_year.1.trimester, Trimester::PartYear);
+
+ let full_year = offering("full year \u{2022} CRN 19175").unwrap();
+
+ assert_eq!(full_year.1.course_reference_number, 19175);
+ assert_eq!(full_year.1.trimester, Trimester::FullYear);
+ }
+
+ #[test]
+ fn title_parser() {
+ assert_eq!(title("HELT 502 ").unwrap().1, "HELT 502");
+ }
+
+ #[test]
+ fn subtitle_parser() {
+ let parsed_subtitle =
+ subtitle("\u{2013} Identification, Assessment and Control of Hazards and Risks")
+ .unwrap();
+
+ // The dash and space were parsed, and are not remaining data.
+ assert_eq!(parsed_subtitle.0, "");
+ // The actual subtitle.
+ assert_eq!(
+ parsed_subtitle.1,
+ "Identification, Assessment and Control of Hazards and Risks"
+ );
+ }
}