argh

Google Fuchsiaチームによって開発された、derive属性ベースの引数パーサー。シンプルで使いやすい設計です。

rustcliderivegooglefuchsia

フレームワーク

argh

概要

arghは、Google Fuchsiaチームによって開発された、derive属性ベースの引数パーサーです。コードサイズの最適化とGoogle Fuchsiaコマンドラインツール仕様への準拠を重視して設計されています。シンプルで使いやすい設計が特徴で、Googleプロジェクトでの採用実績があり、シンプルなAPIを好む開発者に支持されています。

詳細

arghは、Google社のFuchsiaオペレーティングシステムの開発過程で生まれたコマンドライン引数パーサーです。コードサイズの最小化と高いパフォーマンスを重視して設計されており、derive マクロを使用することで直感的で宣言的な引数定義を可能にします。Google社内での利用実績があり、特にサイズ制約がある環境や、シンプルさを重視するプロジェクトで採用されています。

主な特徴

  • Derive マクロ: #[derive(FromArgs)]による自動パーサー生成
  • コードサイズ最適化: 生成されるコードのサイズが最小限に抑えられる
  • シンプルなAPI: 直感的で理解しやすい属性ベースの設計
  • 型安全性: Rustの型システムを活用した強い型付け
  • サブコマンド: enum を使用したサブコマンドサポート
  • 自動ヘルプ: ドキュメントコメントから自動ヘルプ生成
  • Fuchsia準拠: Google Fuchsiaコマンドライン仕様に準拠

メリット・デメリット

メリット

  • 軽量: 非常に小さなコードフットプリント
  • シンプル: 学習コストが低く、すぐに使い始められる
  • 高速: 最適化されたパーサーによる高いパフォーマンス
  • Google品質: Google社内での実績と品質保証
  • 宣言的: 構造体定義でCLI仕様が明確に表現される

デメリット

  • 機能制限: 高度なCLI機能は他のライブラリより限定的
  • エコシステム: Rustエコシステムでの採用は限定的
  • カスタマイズ: 細かいカスタマイズオプションが少ない
  • コミュニティ: clapやstructoptと比較してコミュニティが小さい

主要リンク

書き方の例

use argh::FromArgs;

/// ファイル処理ツール
#[derive(FromArgs, PartialEq, Debug)]
struct AppArgs {
    /// 詳細出力を有効にする
    #[argh(switch, short = 'v')]
    verbose: bool,

    /// 出力フォーマットを指定
    #[argh(option, short = 'f')]
    format: Option<String>,

    /// 処理回数を指定
    #[argh(option, default = "1")]
    count: usize,

    /// 入力ファイルパス
    #[argh(positional)]
    input_file: String,

    /// 出力ファイルパス(オプション)
    #[argh(positional)]
    output_file: Option<String>,

    #[argh(subcommand)]
    command: Option<Commands>,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum Commands {
    /// ファイルを変換する
    Convert(ConvertArgs),
    /// ファイルを検証する
    Validate(ValidateArgs),
    /// 統計情報を表示する
    Stats(StatsArgs),
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "convert")]
/// ファイル形式を変換
struct ConvertArgs {
    /// 変換先フォーマット
    #[argh(option, short = 't')]
    target_format: String,

    /// 品質設定(1-100)
    #[argh(option, default = "80")]
    quality: u8,

    /// 上書きを許可
    #[argh(switch)]
    overwrite: bool,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "validate")]
/// ファイル形式を検証
struct ValidateArgs {
    /// 厳密な検証を実行
    #[argh(switch)]
    strict: bool,

    /// 詳細なレポートを出力
    #[argh(switch)]
    detailed: bool,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "stats")]
/// ファイル統計を表示
struct StatsArgs {
    /// 人間が読みやすい形式で表示
    #[argh(switch, short = 'h')]
    human_readable: bool,

    /// JSON形式で出力
    #[argh(switch)]
    json: bool,
}

fn main() {
    let args: AppArgs = argh::from_env();

    if args.verbose {
        println!("詳細モードが有効です");
        println!("引数: {:#?}", args);
    }

    println!("入力ファイル: {}", args.input_file);
    
    if let Some(output) = &args.output_file {
        println!("出力ファイル: {}", output);
    }

    if let Some(format) = &args.format {
        println!("出力フォーマット: {}", format);
    }

    println!("処理回数: {}", args.count);

    // サブコマンドの処理
    match args.command {
        Some(Commands::Convert(convert_args)) => {
            println!("変換実行:");
            println!("  対象フォーマット: {}", convert_args.target_format);
            println!("  品質: {}", convert_args.quality);
            if convert_args.overwrite {
                println!("  上書きモード有効");
            }
        }

        Some(Commands::Validate(validate_args)) => {
            println!("検証実行:");
            if validate_args.strict {
                println!("  厳密な検証を実行");
            }
            if validate_args.detailed {
                println!("  詳細レポートを生成");
            }
        }

        Some(Commands::Stats(stats_args)) => {
            println!("統計表示:");
            if stats_args.human_readable {
                println!("  人間が読みやすい形式");
            }
            if stats_args.json {
                println!("  JSON形式で出力");
            }
        }

        None => {
            println!("基本的なファイル処理を実行");
        }
    }
}

// より複雑な例:ネストしたサブコマンド
#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum DatabaseCommands {
    /// データベース管理コマンド
    Db(DbArgs),
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "db")]
/// データベース操作
struct DbArgs {
    #[argh(subcommand)]
    operation: DbOperations,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand)]
enum DbOperations {
    /// データベースに接続
    Connect(ConnectArgs),
    /// クエリを実行
    Query(QueryArgs),
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "connect")]
/// データベース接続
struct ConnectArgs {
    /// データベースURL
    #[argh(positional)]
    url: String,

    /// タイムアウト(秒)
    #[argh(option, default = "30")]
    timeout: u32,
}

#[derive(FromArgs, PartialEq, Debug)]
#[argh(subcommand, name = "query")]
/// SQLクエリ実行
struct QueryArgs {
    /// 実行するSQL文
    #[argh(positional)]
    sql: String,

    /// 結果の最大行数
    #[argh(option, default = "100")]
    limit: usize,
}