pubs 0.1.0

This crate simply adds pub for you on your struct or impl functions.
Documentation
/// # PUBS.
/// This crate simply adds pub for you on your struct
/// or impl functions.
///
/// Example usage:
///
/// // main.rs
///
/// use models::Test;
///
/// mod models {
///     use pubs::{PubSkip, pub_methods, pub_struct};
///
///     #[derive(PubSkip)] // Helps you use the "#[skip]" attribute to skip making a given field public
///     #[pub_struct]
///     struct Test {
///         name: String,
///         #[skip] // This makes age private (the default)
///         age: u8,
///     }
///
///     #[pub_methods]
///     impl Test {
///         fn new(n: &str, a: u8) -> Self {
///             Self {
///                 name: n.into(),
///                 age: a,
///             }
///         }
///     }
/// }
///
/// fn main() {
///     let _human = Test::new("Strong the dev", 255);
/// }
///
use proc_macro::TokenStream;
use quote::quote;
use syn::{
    Attribute, DeriveInput, ImplItem, ItemImpl, ItemStruct, Visibility, parse_macro_input,
    token::Pub,
};

// Combines #[make_pub_struct] and #[make_pub_methods]
#[proc_macro_derive(PubSkip, attributes(skip))]
pub fn pub_skip(item: TokenStream) -> TokenStream {
    let input = parse_macro_input!(item as DeriveInput);
    let name = &input.ident;

    match &input.data {
        syn::Data::Struct(_) => {}
        _ => panic!("PubSkip only works on structs"),
    }

    TokenStream::from(quote! {
        impl #name {}
    })
}

/// Marks a struct and its fields as public, unless a field has #[skip]
#[proc_macro_attribute]
pub fn pub_struct(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let mut input = parse_macro_input!(item as ItemStruct);

    // Make the struct itself public
    input.vis = Visibility::Public(Pub::default());

    // Make fields public unless they have #[skip]
    for field in input.fields.iter_mut() {
        if !has_skip(&mut field.attrs) {
            field.vis = Visibility::Public(Pub::default());
        }
    }

    TokenStream::from(quote! { #input })
}

#[proc_macro_attribute]
pub fn pub_methods(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let mut impl_block = parse_macro_input!(item as ItemImpl);

    for item in &mut impl_block.items {
        if let ImplItem::Fn(method) = item
            && !has_skip(&mut method.attrs)
        {
            method.vis = Visibility::Public(Pub::default());
        }
    }

    TokenStream::from(quote! { #impl_block })
}

#[proc_macro_attribute]
pub fn skip(_attr: TokenStream, item: TokenStream) -> TokenStream {
    item
}

/// Helper to check for #[skip]
fn has_skip(attrs: &mut Vec<Attribute>) -> bool {
    let mut field_has_skip: bool = false;
    attrs.retain(|attr| {
        if attr.path().is_ident("skip") {
            field_has_skip = true;
            return false;
        }
        true
    });
    field_has_skip
}