pub mod amazon; pub mod darty; pub mod du_bruit_dans_la_cuisine; pub mod fnac; pub mod ldlc; use crate::price_result::PriceResult; use anyhow::{anyhow, Result}; use arraygen::Arraygen; use scraper::Html; use url::Url; pub trait Parser { /// Create the parser fn new() -> Result where Self: Sized; /// Get the name fn name(&self) -> &'static str; } /// Trait needed to get price from a specific website pub trait PriceParser: Parser { /// Indicate if it can parse this URL fn can_parse(&self, url: &Url) -> bool; /// Parse the html into a price fn parse_price(&self, html: &Html) -> Result; } pub trait SearchParser: PriceParser { /// Return the search URL fn search_url(&self, name: &str) -> Url; /// Return the first occurence of result of the page if any fn search(&self, html: &Html) -> Result>; } macro_rules! gen_list { ( $([$module:ident::$name:ident : $($array:ident),*]),* ) => { #[derive(Arraygen, Debug)] #[gen_array(pub fn get_all: & dyn Parser)] #[gen_array(pub fn get_price: & dyn PriceParser)] #[gen_array(pub fn get_search: & dyn SearchParser)] pub struct List { $( #[in_array(get_all, $($array),* )] $module: $module::$name ),* } impl List { /// Create the list pub fn new() -> Result { Ok(List { $( $module: $module::$name::new()? ),* }) } } }; } gen_list!( [darty::Darty: get_price], [fnac::Fnac: get_price, get_search], [du_bruit_dans_la_cuisine::DuBruitDansLaCuisine: get_price], [ldlc::LDLC: get_price], [amazon::Amazon: get_price, get_search] ); impl List { pub fn get_parser(&self, name: &str) -> Result<&dyn SearchParser> { Ok(*self .get_search() .iter() .find(|&&parser| parser.name().to_lowercase() == name.to_lowercase()) .ok_or(anyhow!("Cannot find the parser {}", name))?) } } #[test] fn test_parser_list() { let parser_list = List::new().unwrap(); assert_eq!(parser_list.get_price().len(), 5); assert_eq!(parser_list.get_search().len(), 2); }