From 793bc83769888a63791bbeb85ed171cea3dc585b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?dj8yf0=CE=BCl?= Date: Mon, 10 Feb 2025 23:14:21 +0200 Subject: [PATCH] review: addresses https://github.com/near-cli-rs/interactive-clap/pull/26#discussion_r1946533737 --- .../docs/clap_enum_for_named_arg_docstring.md | 27 ------- .../docs/structs_from_cli_trait_docstring.md | 70 ------------------ .../docs/structs_input_args_impl_docstring.md | 44 ------------ .../docs/structs_to_cli_trait_docstring.md | 54 -------------- ...tive_clap_context_scope_trait_docstring.md | 26 ------- .../src/derives/interactive_clap/mod.rs | 5 -- .../structs/clap_for_named_arg_enum.rs | 28 ++++++++ .../structs/from_cli_trait.rs | 72 +++++++++++++++++++ .../structs/input_args_impl.rs | 46 ++++++++++++ .../structs/to_cli_trait/mod.rs | 56 +++++++++++++++ ...to_interactive_clap_context_scope_trait.rs | 28 ++++++++ 11 files changed, 230 insertions(+), 226 deletions(-) delete mode 100644 interactive-clap-derive/docs/clap_enum_for_named_arg_docstring.md delete mode 100644 interactive-clap-derive/docs/structs_from_cli_trait_docstring.md delete mode 100644 interactive-clap-derive/docs/structs_input_args_impl_docstring.md delete mode 100644 interactive-clap-derive/docs/structs_to_cli_trait_docstring.md delete mode 100644 interactive-clap-derive/docs/structs_to_interactive_clap_context_scope_trait_docstring.md diff --git a/interactive-clap-derive/docs/clap_enum_for_named_arg_docstring.md b/interactive-clap-derive/docs/clap_enum_for_named_arg_docstring.md deleted file mode 100644 index ea527f8..0000000 --- a/interactive-clap-derive/docs/clap_enum_for_named_arg_docstring.md +++ /dev/null @@ -1,27 +0,0 @@ -derive of helper enum for structs with `#[interactive_clap(named_arg)]` on fields - - -```rust,ignore -struct #name { - #[interactive_clap(named_arg)] - ///Specify a sender - field_name: Sender, -} -``` - -gets transformed -=> - -```rust,ignore -#[derive(Debug, Clone, clap::Parser, interactive_clap_derive::ToCliArgs)] -pub enum ClapNamedArgSenderFor#name { - ///Specify a sender - FieldName(::CliVariant), -} -impl From for ClapNamedArgSenderFor#name { - fn from(item: Sender) -> Self { - Self::FieldName(::CliVariant::from(item)) - } -} -``` - diff --git a/interactive-clap-derive/docs/structs_from_cli_trait_docstring.md b/interactive-clap-derive/docs/structs_from_cli_trait_docstring.md deleted file mode 100644 index 10e0398..0000000 --- a/interactive-clap-derive/docs/structs_from_cli_trait_docstring.md +++ /dev/null @@ -1,70 +0,0 @@ -`interactive_clap::FromCli` derive - -This modules describes derive of `interactive_clap::FromCli` trait for `#name` struct, -which happens during derive of [`crate::InteractiveClap`] for `#name` struct: - -The implementation combines usages of all of [super::structs::to_cli_trait], [super::structs::input_args_impl], -[super::structs::to_interactive_clap_context_scope_trait] - - -derive input `#name` - -```rust,ignore -struct #name { - age: u64, - first_name: String, -} -``` - -gets transformed -=> - -```rust,ignore -impl interactive_clap::FromCli for #name { - type FromCliContext = (); - type FromCliError = color_eyre::eyre::Error; - fn from_cli( - optional_clap_variant: Option<::CliVariant>, - context: Self::FromCliContext, - ) -> interactive_clap::ResultFromCli< - ::CliVariant, - Self::FromCliError, - > - where - Self: Sized + interactive_clap::ToCli, - { - let mut clap_variant = optional_clap_variant.clone().unwrap_or_default(); - if clap_variant.age.is_none() { - clap_variant - .age = match Self::input_age(&context) { - Ok(Some(age)) => Some(age), - Ok(None) => { - return interactive_clap::ResultFromCli::Cancel(Some(clap_variant)); - } - Err(err) => { - return interactive_clap::ResultFromCli::Err(Some(clap_variant), err); - } - }; - } - let age = clap_variant.age.clone().expect("Unexpected error"); - if clap_variant.first_name.is_none() { - clap_variant - .first_name = match Self::input_first_name(&context) { - Ok(Some(first_name)) => Some(first_name), - Ok(None) => { - return interactive_clap::ResultFromCli::Cancel(Some(clap_variant)); - } - Err(err) => { - return interactive_clap::ResultFromCli::Err(Some(clap_variant), err); - } - }; - } - let first_name = clap_variant.first_name.clone().expect("Unexpected error"); - let new_context_scope = InteractiveClapContextScopeFor#name { - age: age.into(), - first_name: first_name.into(), - }; - interactive_clap::ResultFromCli::Ok(clap_variant) - } -} -``` diff --git a/interactive-clap-derive/docs/structs_input_args_impl_docstring.md b/interactive-clap-derive/docs/structs_input_args_impl_docstring.md deleted file mode 100644 index 1bd4785..0000000 --- a/interactive-clap-derive/docs/structs_input_args_impl_docstring.md +++ /dev/null @@ -1,44 +0,0 @@ -per-field input with [inquire::CustomType](https://docs.rs/inquire/0.6.2/inquire/struct.CustomType.html) impl block - -This modules describes derive of input args implementation block for `#name` struct, -which contains functions `input_#field_ident` per each field, -which prompt for value of each field via [inquire::CustomType](https://docs.rs/inquire/0.6.2/inquire/struct.CustomType.html) -, which happens during derive of [`crate::InteractiveClap`] for `#name` struct: - -derive input `#name` - -```rust,ignore -struct #name { - age: u64, - first_name: String, -} -``` - - -gets transformed -=> - -```rust,ignore -impl #name { - fn input_age(_context: &()) -> color_eyre::eyre::Result> { - match inquire::CustomType::new("age").prompt() { - Ok(value) => Ok(Some(value)), - Err( - inquire::error::InquireError::OperationCanceled - | inquire::error::InquireError::OperationInterrupted, - ) => Ok(None), - Err(err) => Err(err.into()), - } - } - fn input_first_name(_context: &()) -> color_eyre::eyre::Result> { - match inquire::CustomType::new("first_name").prompt() { - Ok(value) => Ok(Some(value)), - Err( - inquire::error::InquireError::OperationCanceled - | inquire::error::InquireError::OperationInterrupted, - ) => Ok(None), - Err(err) => Err(err.into()), - } - } -} -``` diff --git a/interactive-clap-derive/docs/structs_to_cli_trait_docstring.md b/interactive-clap-derive/docs/structs_to_cli_trait_docstring.md deleted file mode 100644 index 3f95e0e..0000000 --- a/interactive-clap-derive/docs/structs_to_cli_trait_docstring.md +++ /dev/null @@ -1,54 +0,0 @@ -`interactive_clap::ToCli` derive - -This module describes the derive logic of `#cli_name` struct used as `CliVariant` in -implementation of `interactive_clap::ToCli`, which happens during derive of [`crate::InteractiveClap`] for `#name` struct. - -```rust,ignore -#[derive(Debug, Default, Clone, clap::Parser, interactive_clap::ToCliArgs)] -#[clap(author, version, about, long_about = None)] -pub struct #cli_name { - #( #cli_fields, )* -} - -impl interactive_clap::ToCli for #name { - type CliVariant = #cli_name; -} -``` - -Where `interactive_clap::ToCli` is: - -```rust,ignore -pub trait ToCli { - type CliVariant; -} -``` -Additionally a [`clap::Parser`](https://docs.rs/clap/4.5.24/clap/trait.Parser.html) adapter -for `#name` and `From<#name> for #cli_name` conversion are defined: - -```rust,ignore -impl #name { - pub fn try_parse() -> Result<#cli_name, clap::Error> { - <#cli_name as clap::Parser>::try_parse() - } - - pub fn parse() -> #cli_name { - <#cli_name as clap::Parser>::parse() - } - - pub fn try_parse_from(itr: I) -> Result<#cli_name, clap::Error> - where - I: ::std::iter::IntoIterator, - T: ::std::convert::Into<::std::ffi::OsString> + ::std::clone::Clone, - { - <#cli_name as clap::Parser>::try_parse_from(itr) - } -} - -impl From<#name> for #cli_name { - fn from(args: #name) -> Self { - Self { - #( #fields_conversion, )* - } - } -} -``` diff --git a/interactive-clap-derive/docs/structs_to_interactive_clap_context_scope_trait_docstring.md b/interactive-clap-derive/docs/structs_to_interactive_clap_context_scope_trait_docstring.md deleted file mode 100644 index c4a8438..0000000 --- a/interactive-clap-derive/docs/structs_to_interactive_clap_context_scope_trait_docstring.md +++ /dev/null @@ -1,26 +0,0 @@ -`interactive_clap::ToInteractiveClapContextScope` derive - -This modules describes derive of `interactive_clap::ToInteractiveClapContextScope` trait for `#name` struct, -which happens during derive of [`crate::InteractiveClap`] for `#name` struct: - -derive input `#name` - -```rust,ignore -struct #name { - age: u64, - first_name: String, -} -``` - -gets transformed -=> - -```rust,ignore -impl #name pub struct InteractiveClapContextScopeFor#name { - pub age: u64, - pub first_name: String, -} -impl interactive_clap::ToInteractiveClapContextScope for #name { - type InteractiveClapContextScope = InteractiveClapContextScopeFor#name; -} -``` diff --git a/interactive-clap-derive/src/derives/interactive_clap/mod.rs b/interactive-clap-derive/src/derives/interactive_clap/mod.rs index f0ab5c6..95d2b4a 100644 --- a/interactive-clap-derive/src/derives/interactive_clap/mod.rs +++ b/interactive-clap-derive/src/derives/interactive_clap/mod.rs @@ -177,19 +177,14 @@ quote::quote! { ``` */ pub(crate) mod structs { - #[doc = include_str!("../../../docs/structs_to_cli_trait_docstring.md")] pub(crate) mod to_cli_trait; - #[doc = include_str!("../../../docs/structs_input_args_impl_docstring.md")] mod input_args_impl; - #[doc = include_str!("../../../docs/structs_to_interactive_clap_context_scope_trait_docstring.md")] mod to_interactive_clap_context_scope_trait; - #[doc = include_str!("../../../docs/structs_from_cli_trait_docstring.md")] mod from_cli_trait; - #[doc = include_str!("../../../docs/clap_enum_for_named_arg_docstring.md")] mod clap_for_named_arg_enum; /// these are common field methods, reused by other [structs](super::structs) submodules diff --git a/interactive-clap-derive/src/derives/interactive_clap/structs/clap_for_named_arg_enum.rs b/interactive-clap-derive/src/derives/interactive_clap/structs/clap_for_named_arg_enum.rs index 0de5650..7dfc68d 100644 --- a/interactive-clap-derive/src/derives/interactive_clap/structs/clap_for_named_arg_enum.rs +++ b/interactive-clap-derive/src/derives/interactive_clap/structs/clap_for_named_arg_enum.rs @@ -1,3 +1,31 @@ +/*! +derive of helper enum for structs with `#[interactive_clap(named_arg)]` on fields + + +```rust,ignore +struct #name { + #[interactive_clap(named_arg)] + ///Specify a sender + field_name: Sender, +} +``` + +gets transformed +=> + +```rust,ignore +#[derive(Debug, Clone, clap::Parser, interactive_clap_derive::ToCliArgs)] +pub enum ClapNamedArgSenderFor#name { + ///Specify a sender + FieldName(::CliVariant), +} +impl From for ClapNamedArgSenderFor#name { + fn from(item: Sender) -> Self { + Self::FieldName(::CliVariant::from(item)) + } +} +``` +*/ use proc_macro2::Span; use proc_macro_error::abort_call_site; use quote::{quote, ToTokens}; diff --git a/interactive-clap-derive/src/derives/interactive_clap/structs/from_cli_trait.rs b/interactive-clap-derive/src/derives/interactive_clap/structs/from_cli_trait.rs index afcf528..1f31958 100644 --- a/interactive-clap-derive/src/derives/interactive_clap/structs/from_cli_trait.rs +++ b/interactive-clap-derive/src/derives/interactive_clap/structs/from_cli_trait.rs @@ -1,3 +1,75 @@ +/*! +`interactive_clap::FromCli` derive + +This modules describes derive of `interactive_clap::FromCli` trait for `#name` struct, +which happens during derive of [`crate::InteractiveClap`] for `#name` struct: + +The implementation combines usages of all of [super::structs::to_cli_trait], [super::structs::input_args_impl], +[super::structs::to_interactive_clap_context_scope_trait] + + +derive input `#name` + +```rust,ignore +struct #name { + age: u64, + first_name: String, +} +``` + +gets transformed +=> + +```rust,ignore +impl interactive_clap::FromCli for #name { + type FromCliContext = (); + type FromCliError = color_eyre::eyre::Error; + fn from_cli( + optional_clap_variant: Option<::CliVariant>, + context: Self::FromCliContext, + ) -> interactive_clap::ResultFromCli< + ::CliVariant, + Self::FromCliError, + > + where + Self: Sized + interactive_clap::ToCli, + { + let mut clap_variant = optional_clap_variant.clone().unwrap_or_default(); + if clap_variant.age.is_none() { + clap_variant + .age = match Self::input_age(&context) { + Ok(Some(age)) => Some(age), + Ok(None) => { + return interactive_clap::ResultFromCli::Cancel(Some(clap_variant)); + } + Err(err) => { + return interactive_clap::ResultFromCli::Err(Some(clap_variant), err); + } + }; + } + let age = clap_variant.age.clone().expect("Unexpected error"); + if clap_variant.first_name.is_none() { + clap_variant + .first_name = match Self::input_first_name(&context) { + Ok(Some(first_name)) => Some(first_name), + Ok(None) => { + return interactive_clap::ResultFromCli::Cancel(Some(clap_variant)); + } + Err(err) => { + return interactive_clap::ResultFromCli::Err(Some(clap_variant), err); + } + }; + } + let first_name = clap_variant.first_name.clone().expect("Unexpected error"); + let new_context_scope = InteractiveClapContextScopeFor#name { + age: age.into(), + first_name: first_name.into(), + }; + interactive_clap::ResultFromCli::Ok(clap_variant) + } +} +``` +*/ use proc_macro2::Span; use proc_macro_error::abort_call_site; use quote::{quote, ToTokens}; diff --git a/interactive-clap-derive/src/derives/interactive_clap/structs/input_args_impl.rs b/interactive-clap-derive/src/derives/interactive_clap/structs/input_args_impl.rs index 6adffc2..b1bc233 100644 --- a/interactive-clap-derive/src/derives/interactive_clap/structs/input_args_impl.rs +++ b/interactive-clap-derive/src/derives/interactive_clap/structs/input_args_impl.rs @@ -1,3 +1,49 @@ +/*! +per-field input with [inquire::CustomType](https://docs.rs/inquire/0.6.2/inquire/struct.CustomType.html) impl block + +This modules describes derive of input args implementation block for `#name` struct, +which contains functions `input_#field_ident` per each field, +which prompt for value of each field via [inquire::CustomType](https://docs.rs/inquire/0.6.2/inquire/struct.CustomType.html) +, which happens during derive of [`crate::InteractiveClap`] for `#name` struct: + +derive input `#name` + +```rust,ignore +struct #name { + age: u64, + first_name: String, +} +``` + + +gets transformed +=> + +```rust,ignore +impl #name { + fn input_age(_context: &()) -> color_eyre::eyre::Result> { + match inquire::CustomType::new("age").prompt() { + Ok(value) => Ok(Some(value)), + Err( + inquire::error::InquireError::OperationCanceled + | inquire::error::InquireError::OperationInterrupted, + ) => Ok(None), + Err(err) => Err(err.into()), + } + } + fn input_first_name(_context: &()) -> color_eyre::eyre::Result> { + match inquire::CustomType::new("first_name").prompt() { + Ok(value) => Ok(Some(value)), + Err( + inquire::error::InquireError::OperationCanceled + | inquire::error::InquireError::OperationInterrupted, + ) => Ok(None), + Err(err) => Err(err.into()), + } + } +} +``` +*/ extern crate proc_macro; use proc_macro2::Span; diff --git a/interactive-clap-derive/src/derives/interactive_clap/structs/to_cli_trait/mod.rs b/interactive-clap-derive/src/derives/interactive_clap/structs/to_cli_trait/mod.rs index f84a933..0731b8e 100644 --- a/interactive-clap-derive/src/derives/interactive_clap/structs/to_cli_trait/mod.rs +++ b/interactive-clap-derive/src/derives/interactive_clap/structs/to_cli_trait/mod.rs @@ -1,3 +1,59 @@ +/*! +`interactive_clap::ToCli` derive + +This module describes the derive logic of `#cli_name` struct used as `CliVariant` in +implementation of `interactive_clap::ToCli`, which happens during derive of [`crate::InteractiveClap`] for `#name` struct. + +```rust,ignore +#[derive(Debug, Default, Clone, clap::Parser, interactive_clap::ToCliArgs)] +#[clap(author, version, about, long_about = None)] +pub struct #cli_name { + #( #cli_fields, )* +} + +impl interactive_clap::ToCli for #name { + type CliVariant = #cli_name; +} +``` + +Where `interactive_clap::ToCli` is: + +```rust,ignore +pub trait ToCli { + type CliVariant; +} +``` +Additionally a [`clap::Parser`](https://docs.rs/clap/4.5.24/clap/trait.Parser.html) adapter +for `#name` and `From<#name> for #cli_name` conversion are defined: + +```rust,ignore +impl #name { + pub fn try_parse() -> Result<#cli_name, clap::Error> { + <#cli_name as clap::Parser>::try_parse() + } + + pub fn parse() -> #cli_name { + <#cli_name as clap::Parser>::parse() + } + + pub fn try_parse_from(itr: I) -> Result<#cli_name, clap::Error> + where + I: ::std::iter::IntoIterator, + T: ::std::convert::Into<::std::ffi::OsString> + ::std::clone::Clone, + { + <#cli_name as clap::Parser>::try_parse_from(itr) + } +} + +impl From<#name> for #cli_name { + fn from(args: #name) -> Self { + Self { + #( #fields_conversion, )* + } + } +} +``` +*/ use proc_macro2::TokenStream; use quote::quote; diff --git a/interactive-clap-derive/src/derives/interactive_clap/structs/to_interactive_clap_context_scope_trait.rs b/interactive-clap-derive/src/derives/interactive_clap/structs/to_interactive_clap_context_scope_trait.rs index 9da2d3a..93f980a 100644 --- a/interactive-clap-derive/src/derives/interactive_clap/structs/to_interactive_clap_context_scope_trait.rs +++ b/interactive-clap-derive/src/derives/interactive_clap/structs/to_interactive_clap_context_scope_trait.rs @@ -1,3 +1,31 @@ +/*! +`interactive_clap::ToInteractiveClapContextScope` derive + +This modules describes derive of `interactive_clap::ToInteractiveClapContextScope` trait for `#name` struct, +which happens during derive of [`crate::InteractiveClap`] for `#name` struct: + +derive input `#name` + +```rust,ignore +struct #name { + age: u64, + first_name: String, +} +``` + +gets transformed +=> + +```rust,ignore +impl #name pub struct InteractiveClapContextScopeFor#name { + pub age: u64, + pub first_name: String, +} +impl interactive_clap::ToInteractiveClapContextScope for #name { + type InteractiveClapContextScope = InteractiveClapContextScopeFor#name; +} +``` +*/ use proc_macro2::Span; use quote::quote;