forward-methods 0.0.2

A derive macro for forwarding methods from composed objects
Documentation
use syn::parse::{Parse, ParseStream};
use syn::{Error, Result, Token};

use crate::model::{Delegate, Method};

impl Parse for Delegate {
    fn parse(input: ParseStream) -> Result<Self> {
        if input.peek(Token![fn]) {
            let meth: Method = input.parse()?;
            let mut methods = vec![meth];

            while input.peek(Token![,]) && input.peek2(Token![fn]) {
                _ = input.parse::<Token![,]>();

                let meth: Method = input.parse()?;
                methods.push(meth)
            }

            Ok(Delegate::MethodList(methods))
        } else {
            Err(Error::new(
                input.span(),
                "delegates must be declared as a list of methods in the form 'fn ident(arg1, arg2, ...) -> Return'"
            ))
        }
    }
}

#[cfg(test)]
mod tests {
    use proc_macro2::TokenStream;
    use quote::quote;
    use test_case::test_case;

    use crate::model::{Delegate, MethodBuilder};

    #[test_case(
        quote!(fn test_a(self), fn test_b(self)),
        Delegate::MethodList(vec![
            MethodBuilder::default().ident("test_a").rcv().build().unwrap(),
            MethodBuilder::default().ident("test_b").rcv().build().unwrap()
        ]);
        "should parse delegate method list"
    )]
    fn should_parse_delegate(input: TokenStream, want: Delegate) {
        let del = syn::parse2::<Delegate>(input).unwrap();

        assert_eq!(del, want)
    }

    #[test_case(
        quote!(invalid),
        "delegates must be declared as a list of methods in the form 'fn ident(arg1, arg2, ...) -> Return'";
        "should require method list format"
    )]
    fn should_fail_to_parse_delegate(input: TokenStream, want: &str) {
        let err = syn::parse2::<Delegate>(input).unwrap_err();

        assert_eq!(err.to_string(), want)
    }
}