符合人体工程学的运行时默认参数以及 Clap 派生 API

问题描述 投票:0回答:1

我一直在使用 Clap 的

derive
API,但最近遇到了一个情况,我需要在运行时确定一些参数的默认值。

我的代码的简化版本是这样的,基本上直接取自 我找到了这个文档,了解如何在 Clap 中组合基于 derive

 和基于 Builder 的 API。

#[derive(clap::Parser)] #[command(author, version, about, long_about = None)] struct Args { #[arg(short, long, default_value_t = {".".to_string()})] repo: String, // (... other args with static defaults) #[command(flatten)] runtime_default: RuntimeDefaultArgs, } struct RuntimeDefaultArgs { result_db: PathBuf, // (... other args with dynamic defaults) } impl FromArgMatches for RuntimeDefaultArgs { fn from_arg_matches(matches: &ArgMatches) -> Result<Self, clap::Error> { let mut matches = matches.clone(); Self::from_arg_matches_mut(&mut matches) } fn from_arg_matches_mut(matches: &mut ArgMatches) -> Result<Self, clap::Error> { Ok(Self { result_db: matches.get_one::<PathBuf>("result-db").unwrap().to_owned(), }) } fn update_from_arg_matches(&mut self, matches: &ArgMatches) -> Result<(), clap::Error> { let mut matches = matches.clone(); self.update_from_arg_matches_mut(&mut matches) } fn update_from_arg_matches_mut(&mut self, matches: &mut ArgMatches) -> Result<(), clap::Error> { self.result_db = matches.get_one::<PathBuf>("result-db").unwrap().to_owned(); Ok(()) } } // This is where we actually define the arguments with dynamic defaults. impl clap::Args for RuntimeDefaultArgs { fn augment_args(cmd: clap::Command) -> clap::Command { let default_db = calculate_default_db_path(); cmd.arg( Arg::new("result-db") .long("result-db") .value_parser(value_parser!(PathBuf)) .default_value(default_db.to_str()), ) } fn augment_args_for_update(cmd: clap::Command) -> clap::Command { Self::augment_args(cmd) } }
这对于当前代码来说还不错,但现在我想添加其他子命令,每个子命令都有自己的参数和运行时计算的默认值。所以它似乎遵循这种模式,我需要为每个子命令再次实现这两个重复的特征。

我在 Clap 中缺少什么东西可以让这件事变得更容易吗?看来这个问题根本不存在于构建器 API 中。这是有道理的,因为派生 API 从根本上讲是在“编译时”做一些事情,因此从 PoV 来看,混合

derive

 和 Builder API 似乎是正确的方向。但也许有更方便的方法来做到这一点?

rust clap
1个回答
0
投票
对于实现所需特征的任何参数类型,包括

Display

,您可以这样做:

use std::path::PathBuf; use clap::Parser; #[derive(Parser, Debug, Clone)] pub struct Opts { #[clap(long, default_value_t = default_result_db())] pub result_db: String, } fn default_result_db() -> String { todo!(); }
由于

PathBuf

不直接实现
Display
,你可以制作一个包装器:

use std::ops::Deref; use clap::Parser; use std::fmt::{self, Debug, Display, Formatter}; use std::path::PathBuf; use std::str::FromStr; #[derive(Parser, Debug, Clone)] pub struct Opts { #[clap(long, default_value_t = default_result_db())] pub result_db: DisplayablePathBuf, } fn default_result_db() -> DisplayablePathBuf { todo!(); } #[derive(Clone)] pub struct DisplayablePathBuf(PathBuf); impl FromStr for DisplayablePathBuf { type Err = <PathBuf as FromStr>::Err; fn from_str(s: &str) -> Result<Self, Self::Err> { PathBuf::from_str(s).map(Self) } } impl Debug for DisplayablePathBuf { fn fmt(&self, f: &mut Formatter) -> fmt::Result { Debug::fmt(&self.0, f) } } impl Display for DisplayablePathBuf { fn fmt(&self, f: &mut Formatter) -> fmt::Result { Display::fmt(&self.0.display(), f) } } impl Deref for DisplayablePathBuf { type Target = PathBuf; fn deref(&self) -> &PathBuf { &self.0 } }
    
© www.soinside.com 2019 - 2024. All rights reserved.