Как я могу получить доступ к переменной, определенной во время выполнения, в определениях stuctopt?

Я хотел бы иметь возможность использовать значение переменной (или еще лучше, возврат function(arg)) в качестве строки about для программы CLI, определенной с помощью structopt. Конечная цель - это полностью локализованный интерфейс командной строки, который определяет системный язык или переменную ENV и загружает локализованные строки, которые встраиваются в сообщение --help и т. Д.

По умолчанию используется комментарий документации:

/// My about string
#[derive(StructOpt)]
struct Cli {}

Я обнаружил, что могу вместо этого передать введенную вручную строку:

#[derive(StructOpt)]
#[structopt(about = "My about string")]
struct Cli {}

Это на один шаг ближе, но я действительно хочу передать переменную:

let about: &str = "My about string";
#[derive(StructOpt)]
#[structopt(about = var!(about))]
struct Cli {}

Этот последний блок является псевдокодом, потому что я не знаю, какой синтаксис использовать для этого. В конце концов, мне понадобится нечто большее, чем просто фрагмент одной строки, но я решил, что это место для начала.

Как я могу передать такие значения в structopt? Нужно ли мне каким-то образом получить доступ к базовым интерфейсам хлопка?


person Caleb    schedule 27.04.2020    source источник


Ответы (1)


StructOpt просто добавляет макрос извлечения и соответствующую черту поверх clap. Ящик для хлопков имеет функцию для установки о сообщении во время выполнения, поэтому нам просто нужно его добавить. Если мы посмотрим на как работает from_args, мы видно, что он создает структуру clap App перед тем, как превратить ее в определяемую пользователем структуру.

Таким образом, чтобы делать то, что вы хотите:

use structopt::StructOpt;

fn get_localized_about() -> &'static str {
    "localized string"
}

#[derive(Debug, StructOpt)]
struct Foo {}

fn main() {
    let foo = Foo::from_clap(&Foo::clap().about(get_localized_about()).get_matches());
    println!("{:#?}", foo);
}
person Timidger    schedule 27.04.2020
comment
Спасибо, это определенно ответ на тот вопрос, который я задал. К сожалению, мне кажется, что я слишком упростил вопрос. Это отлично подходит для установки информации .about(), но я не могу добиться такого же эффекта для других вещей, таких как мои параметры, подкоманды и их аргументы. Я хочу локализовать весь вывод, а не только строку About. Если я попробую примерно тот же метод с .arg(), я смогу только увидеть, как добавлять аргументы, но не изменить описание тех, которые были добавлены через StructOpt. Я лаю не на то дерево? StructOpt казался прекрасным, но, возможно, мне просто следует использовать Clap напрямую. - person Caleb; 27.04.2020
comment
Похоже, вы могли бы захотеть изучить функцию yaml как часть ящика. Вы можете указать все в отдельном файле, а затем загрузить в разные, в зависимости от локализации, сообщенной системой. Это описано в README, здесь - person Timidger; 27.04.2020
comment
@Tinmidger На самом деле я уже читал о поддержке YAML Clap, но есть две проблемы с ее использованием. Во-первых, все документы предполагают, что это выбор времени компиляции, когда вы создаете двоичные файлы на желаемом языке. Мне нужен выбор языка во время выполнения, а не время компиляции. Во-вторых, мои переводы поступают из Fluent, и я не в восторге от того, что помещаю их в YAML. Я мог бы автоматически сгенерировать YAML, если бы первая проблема не была блокировщиком. - person Caleb; 27.04.2020
comment
1) load_yaml! - время компиляции (поскольку это макрос), но если вы посмотрите его исходный код, его достаточно легко сделать во время выполнения. Если вам не важен двоичный размер, вы можете include_str! все локализованные файлы yaml (или во время выполнения работать с файлами, если вы этого не хотите), а затем выбрать, какой из них использовать. Однако тот факт, что переводы выполняются с свободного языка, действительно усложняет задачу. В этом случае я бы отбросил StructOpt и просто использовал clap или использовал один файл yaml и шаблон на основе локализации - person Timidger; 27.04.2020
comment
Я здесь около трех дней в Rust, возился с источниками макросов, чтобы переместить код времени компиляции во время выполнения, похоже, что ему, возможно, придется подождать неделю или около того. Но спасибо за советы. Я определенно хотел бы встроить строки в двоичный файл, потому что у меня возникают проблемы с путями, если я пытаюсь загрузить ресурсы. Есть три сценария запуска, и мне нужно сделать некоторое обнаружение пути, чтобы выяснить, какой это, прежде чем я смогу найти файлы YAML, и если этот процесс пойдет не так, я хотел бы иметь возможность отображать локализованные сообщения об ошибках! Классический улов 22. - person Caleb; 27.04.2020
comment
Другой улов 22 заключается в том, что языковой стандарт должен исходить от LC_LANG (или эквивалента платформы). Эта часть уже работает ... но предполагается, что ее можно перезаписать с помощью флага параметра CLI --language tr_TR или чего-то подобного. Даже с помощью Clap напрямую я не могу понять, как анализировать аргументы для языкового флага перед установкой свойств справки arg. - person Caleb; 27.04.2020
comment
Суть макроса в том, что это просто удобство - если вам нужно, чтобы он работал во время выполнения, вы можете взять его источник и удалить все использование макросов, пока не дойдете до того момента, когда вы хотите переместить его во время выполнения. Также изучите сценарии сборки, чтобы узнать, может ли это вам помочь. Если у вас есть какие-либо другие конкретные вопросы, я предлагаю задать еще один вопрос о stackoverflow, поскольку он вышел за рамки исходного вопроса :) - person Timidger; 28.04.2020
comment
Спасибо за предложения. Насколько я могу судить, сценарии сборки могут передавать вещи только в основной код через переменные ENV ... или генерировать исходный код, который, конечно, загружается. Насколько я могу судить, для этого варианта использования нет особого преимущества по сравнению с основной программой, выполняющей загрузку. - person Caleb; 28.04.2020