reval 0.7.6

Simple Rust expression evaluator
Documentation
use crate::{expr::Expr, parse::Error, ruleset::rule::Rule};
use itertools::Itertools;

impl Rule {
    pub fn parse(input: &str) -> Result<Self, Error> {
        let mut comment_lines = input
            .lines()
            .filter_map(|line| line.trim_start().strip_prefix("//").map(str::trim));

        match comment_lines.next() {
            Some(name_line) => {
                let name = name_line.trim();
                let description = comment_lines.map(|line| line.trim()).join("\n");

                Ok(Rule::new(name, description, Expr::parse(input)?))
            }
            None => Err(Error::MissingRuleName),
        }
    }
}

#[cfg(test)]
mod when_parsing_rules {
    use super::*;

    #[test]
    fn should_error_when_rule_name_missing() {
        assert!(matches!(Rule::parse("i3"), Err(Error::MissingRuleName)));
    }

    #[test]
    fn should_parse_rule_name() {
        assert_eq!(Rule::parse("//rule name\ni3").unwrap().name(), "rule name");
    }

    #[test]
    fn should_trim_rule_name() {
        assert_eq!(
            Rule::parse("// valid rule name   \t\ni3").unwrap().name(),
            "valid rule name"
        );
    }

    #[test]
    fn should_parse_comments_as_description() {
        assert_eq!(
            Rule::parse("//name\n//descr1\ni3").unwrap().description(),
            Some("descr1")
        );
    }

    #[test]
    fn should_error_when_no_expression() {
        assert!(Rule::parse("//name\n//descr1\n").is_err());
    }

    #[test]
    fn should_error_when_expression_invalid() {
        assert!(Rule::parse("//name\n34").is_err(),);
    }

    #[test]
    fn should_parse_multiline_expression() {
        assert_eq!(
            Rule::parse("//name\n// descr1\n// descr2  \ni3")
                .unwrap()
                .description(),
            Some("descr1\ndescr2")
        );
    }

    #[test]
    fn should_parse_comments_in_between_expression() {
        assert_eq!(
            Rule::parse("//name\n// descr1  \t\ni3\n// descr2")
                .unwrap()
                .description(),
            Some("descr1\ndescr2")
        );
    }
}