From 1cb4f0ca5db4d61fdcacd92f328a16ee46ca7b54 Mon Sep 17 00:00:00 2001 From: holmofy Date: Sat, 3 Aug 2024 20:30:42 +0800 Subject: [PATCH] fix macros --- reqwest-scraper-macros/src/css_selector.rs | 69 ++++++++++++++-------- reqwest-scraper-macros/src/xpath.rs | 12 ++-- 2 files changed, 51 insertions(+), 30 deletions(-) diff --git a/reqwest-scraper-macros/src/css_selector.rs b/reqwest-scraper-macros/src/css_selector.rs index bca11e7..de2c220 100644 --- a/reqwest-scraper-macros/src/css_selector.rs +++ b/reqwest-scraper-macros/src/css_selector.rs @@ -1,17 +1,22 @@ +use std::str::FromStr; + use crate::utils::syn::{get_type_detail, PathType}; -use darling::{ast::Data, util::Flag, FromDeriveInput, FromField}; +use darling::{ast::Data, util::Flag, FromDeriveInput, FromField, FromMeta}; use proc_macro2::{Span, TokenStream}; use quote::quote; use scraper::Selector; use syn::{spanned::Spanned, DeriveInput, Error, Result}; +#[derive(Debug)] +struct CssSelector(String); + #[derive(Debug, FromDeriveInput)] #[darling(attributes(selector), supports(struct_named))] struct CssSelectorScraper { ident: syn::Ident, generics: syn::Generics, data: Data<(), CssSelectorStructField>, - path: Option, + path: Option, } #[derive(Debug, FromField)] @@ -48,11 +53,10 @@ pub fn expand_derive_from_response(input: DeriveInput) -> syn::Result { - check_selector(&selector)?; quote! { - impl #impl_generics reqwest_scraper::FromCssSelector for #type_name #ty_generics #where_clause { - type CssSelectorExtractResult = reqwest_scraper::error::Result>; - fn from_html(html: reqwest_scraper::css_selector::Html) -> Self::CssSelectorExtractResult { + impl #impl_generics ::reqwest_scraper::FromCssSelector for #type_name #ty_generics #where_clause { + type CssSelectorExtractResult = ::reqwest_scraper::error::Result>; + fn from_html(html: ::reqwest_scraper::css_selector::Html) -> Self::CssSelectorExtractResult { let list = html.select(#selector)?; let mut result: Vec = std::vec::Vec::new(); @@ -69,9 +73,9 @@ pub fn expand_derive_from_response(input: DeriveInput) -> syn::Result quote! { - impl #impl_generics reqwest_scraper::FromCssSelector for #type_name #ty_generics #where_clause { - type CssSelectorExtractResult = reqwest_scraper::error::Result; - fn from_html(html: reqwest_scraper::css_selector::Html) -> Self::CssSelectorExtractResult { + impl #impl_generics ::reqwest_scraper::FromCssSelector for #type_name #ty_generics #where_clause { + type CssSelectorExtractResult = ::reqwest_scraper::error::Result; + fn from_html(html: ::reqwest_scraper::css_selector::Html) -> Self::CssSelectorExtractResult { let item = &html; Ok(Self { @@ -103,17 +107,16 @@ fn generate_field_extractors(fields: Vec<&CssSelectorStructField>) -> Result { - check_selector(&selector)?; match ty { PathType::Option=>quote! { #field_ident: item.select(#selector)?.first().and_then(#extractor).into() }, PathType::Vector=>quote! { #field_ident: item.select(#selector)?.iter() - .map(|item|std::option::Option::Some(item).and_then(#extractor)) + .map(|item|::std::option::Option::Some(item).and_then(#extractor)) .filter(|o|o.is_some()) .map(|o|o.unwrap().into()) - .collect::>() + .collect::<::std::vec::Vec<_>>() }, PathType::Other=>quote! { #field_ident: item.select(#selector)?.first().and_then(#extractor).unwrap_or(#default.into()).into() @@ -123,7 +126,7 @@ fn generate_field_extractors(fields: Vec<&CssSelectorStructField>) -> Result { match ty { PathType::Option=>quote! { - #field_ident: std::option::Option::Some(item).and_then(#extractor).into() + #field_ident: ::std::option::Option::Some(item).and_then(#extractor).into() }, PathType::Vector=>{ return Err(Error::new( @@ -132,7 +135,7 @@ fn generate_field_extractors(fields: Vec<&CssSelectorStructField>) -> Resultquote! { - #field_ident: std::option::Option::Some(item).and_then(#extractor).unwrap_or(#default.into()).into() + #field_ident: ::std::option::Option::Some(item).and_then(#extractor).unwrap_or(#default.into()).into() } } }, @@ -141,15 +144,6 @@ fn generate_field_extractors(fields: Vec<&CssSelectorStructField>) -> Result syn::Result<()> { - Selector::parse(selector).map(|_| ()).map_err(|err| { - syn::Error::new( - Span::call_site(), - format!("invalid css selector `{}`: {:?}", selector, err), - ) - }) -} - #[derive(Debug)] pub enum Extractor { Name, @@ -220,12 +214,39 @@ impl quote::ToTokens for Extractor { Self::Text => quote! {|e|Some(e.text())}, Self::Html => quote! {|e|Some(e.html())}, Self::InnerHtml => quote! {|e|Some(e.inner_html())}, - Self::HasClass(class) => quote! {|e|Some(e.has_class(#class,reqwest_scraper::css_selector::CaseSensitivity::CaseSensitive))}, + Self::HasClass(class) => quote! {|e|Some(e.has_class(#class,::reqwest_scraper::css_selector::CaseSensitivity::CaseSensitive))}, Self::Attr(attr) => quote! {|e|e.attr(#attr).map(|v|v.to_string())}, }) } } +impl FromStr for CssSelector { + type Err = syn::Error; + + fn from_str(selector: &str) -> Result { + Selector::parse(selector).map(|_| ()).map_err(|err| { + syn::Error::new( + Span::call_site(), + format!("invalid css selector `{}`: {:?}", selector, err), + ) + }); + Ok(CssSelector(selector.to_string())) + } +} + +impl FromMeta for CssSelector { + fn from_string(s: &str) -> darling::Result { + s.parse().map_err(darling::Error::from) + } +} + +impl quote::ToTokens for CssSelector { + fn to_tokens(&self, tokens: &mut TokenStream) { + let selector = &self.0; + tokens.extend(quote! {#selector}) + } +} + #[test] fn test_select_list() -> Result<()> { let input = r#" diff --git a/reqwest-scraper-macros/src/xpath.rs b/reqwest-scraper-macros/src/xpath.rs index b21234a..b0d827c 100644 --- a/reqwest-scraper-macros/src/xpath.rs +++ b/reqwest-scraper-macros/src/xpath.rs @@ -40,9 +40,9 @@ pub fn expand_derive_from_response(input: DeriveInput) -> syn::Result { let field_extractors = generate_list_item_field_extractors(fields)?; quote! { - impl #impl_generics reqwest_scraper::FromXPath for #type_name #ty_generics #where_clause { - type XPathExtractResult = reqwest_scraper::error::Result>; - fn from_xhtml(html: reqwest_scraper::xpath::XHtml) -> Self::XPathExtractResult { + impl #impl_generics ::reqwest_scraper::FromXPath for #type_name #ty_generics #where_clause { + type XPathExtractResult = ::reqwest_scraper::error::Result>; + fn from_xhtml(html: ::reqwest_scraper::xpath::XHtml) -> Self::XPathExtractResult { let list = html.select(#xpath)?.as_nodes(); let mut result: Vec = std::vec::Vec::new(); @@ -61,9 +61,9 @@ pub fn expand_derive_from_response(input: DeriveInput) -> syn::Result { let field_extractors = generate_field_extractors(fields)?; quote! { - impl #impl_generics reqwest_scraper::FromXPath for #type_name #ty_generics #where_clause { - type XPathExtractResult = reqwest_scraper::error::Result; - fn from_xhtml(html: reqwest_scraper::xpath::XHtml) -> Self::XPathExtractResult { + impl #impl_generics ::reqwest_scraper::FromXPath for #type_name #ty_generics #where_clause { + type XPathExtractResult = ::reqwest_scraper::error::Result; + fn from_xhtml(html: ::reqwest_scraper::xpath::XHtml) -> Self::XPathExtractResult { let item = &html; Ok(Self {