use super::{Loader, MacroCall, MacroError, Parser};
use crate::value::{DuplicateStrategy, ParserFlags};
use std::path::PathBuf;
#[derive(Debug, Default)]
pub struct ParserBuilder {
parser: Parser,
}
impl ParserBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn with_flags(mut self, flags: ParserFlags) -> Self {
self.parser.set_flags(flags);
self
}
pub fn with_priority(mut self, priority: u8) -> Self {
self.parser.set_priority(priority);
self
}
pub fn with_strategy(mut self, strategy: DuplicateStrategy) -> Self {
self.parser.set_strategy(strategy);
self
}
pub fn with_variable(mut self, name: impl Into<String>, value: impl Into<String>) -> Self {
self.parser.register_variable(name, value);
self
}
pub fn with_variables<I, K, V>(mut self, variables: I) -> Self
where
I: IntoIterator<Item = (K, V)>,
K: Into<String>,
V: Into<String>,
{
for (name, value) in variables {
self.parser.register_variable(name, value);
}
self
}
pub fn with_variable_handler(
mut self,
handler: impl FnMut(&str) -> Option<String> + 'static,
) -> Self {
self.parser.set_variable_handler(handler);
self
}
pub fn with_macro(
mut self,
name: impl Into<String>,
handler: impl Fn(&mut MacroCall<'_>) -> Result<(), MacroError> + 'static,
) -> Self {
self.parser.register_macro(name, handler);
self
}
pub fn with_context_macro(
mut self,
name: impl Into<String>,
handler: impl Fn(&mut MacroCall<'_>) -> Result<(), MacroError> + 'static,
) -> Self {
self.parser.register_context_macro(name, handler);
self
}
pub fn with_loader(mut self, loader: impl Loader + 'static) -> Self {
self.parser.set_loader(loader);
self
}
pub fn with_base_dir(mut self, dir: impl Into<PathBuf>) -> Self {
self.parser.set_base_dir(dir);
self
}
pub fn with_search_path<I, S>(mut self, dirs: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.parser.set_search_path(dirs);
self
}
pub fn with_max_input_bytes(mut self, limit: u64) -> Self {
self.parser.set_max_input_bytes(Some(limit));
self
}
pub fn with_inherit_depth_limit(mut self, limit: usize) -> Self {
self.parser.set_inherit_depth_limit(limit);
self
}
pub fn build(self) -> Parser {
self.parser
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parse::MemoryLoader;
use crate::value::UclValue;
#[test]
fn builder_sets_what_the_setters_set() {
let mut loader = MemoryLoader::new();
loader.add_file("/cfg/part.conf", "b = 2\n");
let mut parser = ParserBuilder::new()
.with_flags(ParserFlags::KEY_LOWERCASE)
.with_priority(3)
.with_strategy(DuplicateStrategy::Rewrite)
.with_variables([("A", "x"), ("AB", "y")])
.with_variable("C", "z")
.with_variable_handler(|name| (name == "H").then(|| "h".to_string()))
.with_loader(loader)
.with_base_dir("/cfg")
.with_search_path(["/cfg"])
.with_max_input_bytes(1000)
.with_inherit_depth_limit(2000)
.build();
assert_eq!(parser.flags(), ParserFlags::KEY_LOWERCASE);
assert_eq!(parser.inherit_depth_limit(), 2000);
assert_eq!(parser.base_dir(), Some(std::path::Path::new("/cfg")));
assert_eq!(parser.search_path(), Some(&["/cfg".to_string()][..]));
assert_eq!(parser.max_input_bytes(), Some(1000));
let v = parser
.parse(b"K = \"$AB ${C} ${H}\"\nk = 2\n.include \"part.conf\"")
.unwrap();
let o = v.as_object().unwrap();
assert_eq!(o["k"], UclValue::Integer(2));
assert_eq!(o.entry("k").unwrap().len(), 1);
assert_eq!(o.entry("k").unwrap().slots()[0].priority(), 3);
assert_eq!(o["b"], UclValue::Integer(2));
let mut parser = ParserBuilder::new()
.with_variables([("A", "x"), ("AB", "y")])
.with_variable("C", "z")
.with_variable_handler(|name| (name == "H").then(|| "h".to_string()))
.build();
let v = parser.parse(b"s = \"$AB ${C} ${H} ${I}\"").unwrap();
assert_eq!(v.as_object().unwrap()["s"].as_str(), Some("xB z h ${I}"));
}
}