use serde::Deserialize; use std::fs; use std::path::Path; use std::sync::Arc; use crate::law::{self, responsible::*}; use crate::law::{ClassifierApplicable, LawBuilder}; use crate::misc::Error; use crate::paragraph::Parser; // TODO: more generic fn create_classifier(match_function: &str) -> Result { let func: ClassifierApplicable = match match_function { "contains" => Arc::new(contains), "starts_with_roman_number" => Arc::new(starts_with_roman_number), "contains_at_start" => Arc::new(contains_at_start), "starts_with_number" => Arc::new(starts_with_number), "starts_with_letter" => Arc::new(starts_with_letter), "starts_with_dash" => Arc::new(starts_with_dash), "starts_with_uppercaseletter" => Arc::new(starts_with_uppercaseletter), "contains_without_unter" => Arc::new(contains_without_unter), _ => { return Err(Error::new(&format!( "Unknown match function: {}", match_function ))) } }; Ok(func) } #[derive(Debug, Deserialize)] pub struct Config { law: Law, #[serde(default)] parser: ParserConfig, } impl Config { pub fn load>(path: P) -> Result<(usize, LawBuilder, Parser), Error> { let config_str = fs::read_to_string(path)?; let config: Config = toml::from_str(&config_str)?; let mut builder = LawBuilder::new(); for classifier in config.law.classifiers { let to_add = law::Classifier::new( &classifier.name, create_classifier(&classifier.match_function)?, ); if classifier.is_root { builder.add_classifier(to_add.root()); } else { builder.add_classifier(to_add); } } let mut parser = Parser::new(); for to_remove in config.parser.remove_strings { parser.add_string_to_remove(&to_remove); } for to_replace in config.parser.replace_rules { parser.add_string_to_replace(&to_replace.find, &to_replace.replace_with); } Ok((config.law.id, builder, parser)) } } #[derive(Debug, Deserialize)] struct Law { id: usize, classifiers: Vec, } #[derive(Debug, Deserialize)] struct Classifier { name: String, is_root: bool, match_function: String, } #[derive(Debug, Deserialize, Default)] struct ParserConfig { #[serde(default)] //okay to not have this part in the config remove_strings: Vec, #[serde(default)] //okay to not have this part in the config replace_rules: Vec, } #[derive(Debug, Deserialize)] struct ReplaceRule { find: String, replace_with: String, } #[cfg(test)] mod tests { use std::fs; use super::Config; #[test] fn all_configs_are_deserializable() { let configs = fs::read_dir("./data/configs").expect("No folder with config files"); for config in configs { let path = format!("{}", config.unwrap().path().display()); Config::load(&path).unwrap(); } } }