Something went wrong. Try again.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106use std::fs;use std::path::Path;use std::sync::Arc;
pub static BUILTINS: &[(&str, &str)] = &[ ("example", include_str!("../scripts/example.lua")), ("theverge", include_str!("../scripts/theverge.lua")), ( "eldenring-patch-notes", include_str!("../scripts/eldenring-patch-notes.lua"), ), ( "overwatch-patch-notes", include_str!("../scripts/overwatch-patch-notes.lua"), ), ( "toby-fox-newsletters", include_str!("../scripts/toby-fox-newsletters.lua"), ), ( "humble-bundles", include_str!("../scripts/humble-bundles.lua"), ), ( "thedailybeast", include_str!("../scripts/thedailybeast.lua"), ),];
#[derive(Debug)]pub enum MethodError { Io(std::io::Error), Syntax(mlua::Error),}
impl std::fmt::Display for MethodError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { MethodError::Io(e) => write!(f, "failed to read method script: {e}"), MethodError::Syntax(e) => write!(f, "method script has a syntax error: {e}"), } }}
impl std::error::Error for MethodError {}
/// Resolves a `method` string from a `site{}` entry to Lua source: a builtin/// name is checked first, otherwise the string is treated as a path (relative/// to the config file's directory) to an operator-authored script. Syntax is/// checked eagerly so a broken script fails at startup, not mid-schedule.pub fn resolve_method(method: &str, base_dir: &Path) -> Result<Arc<str>, MethodError> { if let Some((_, source)) = BUILTINS.iter().find(|(name, _)| *name == method) { return Ok(Arc::from(*source)); }
let path = base_dir.join(method); let source = fs::read_to_string(&path).map_err(MethodError::Io)?;
mlua::Lua::new() .load(&source) .into_function() .map_err(MethodError::Syntax)?;
Ok(Arc::from(source))}
#[cfg(test)]mod tests { use super::*;
fn scratch_dir() -> std::path::PathBuf { let dir = std::env::temp_dir().join(format!("luafeed-method-test-{}", std::process::id())); fs::create_dir_all(&dir).unwrap(); dir }
#[test] fn resolves_builtin_by_name() { let source = resolve_method("example", Path::new("/nonexistent")).unwrap(); assert!(source.contains("find_all")); }
#[test] fn resolves_external_file_path() { let dir = scratch_dir(); fs::write(dir.join("custom.lua"), "local root = ...\nreturn {}\n").unwrap(); let source = resolve_method("custom.lua", &dir).unwrap(); assert!(source.contains("return {}")); }
#[test] fn rejects_nonexistent_path() { let dir = scratch_dir(); let err = resolve_method("missing.lua", &dir).unwrap_err(); assert!(matches!(err, MethodError::Io(_))); }
#[test] fn rejects_syntax_errors() { let dir = scratch_dir(); fs::write(dir.join("broken.lua"), "this is not valid lua (((").unwrap(); let err = resolve_method("broken.lua", &dir).unwrap_err(); assert!(matches!(err, MethodError::Syntax(_))); }}