Esempio n. 1
0
        /// <summary>
        /// 一連のコマンドライン・オプションの値をその定義情報にしたがい解決します。
        /// このメソッドはコマンドライン引数とアプリケーション構成ファイルの設定情報を入力として、
        /// コマンドライン・オプションの定義情報に規定された情報を読み取ります。
        /// </summary>
        /// <param name="rawArgs">コマンドライン引数</param>
        /// <param name="settings">アプリケーション構成ファイルの設定情報</param>
        /// <param name="vo">パース結果を設定するバリュー・オブジェクト</param>
        void ResolveOptions(IEnumerable <string> rawArgs, IDictionary <string, string> settings, T vo)
        {
            // 1. コマンドライン引数の処理(前段階)

            // まず解決待ちの引数と解決できなかった引数を格納するキューを用意する
            // *最終的に解決不可となったものは、コマンドライン・オプションやその引数ではなく
            // コマンドそのものの引数であると見なされ、ICommandLine.SetterDelegateに渡される。
            var toArgResolve    = new Queue <string>(rawArgs);
            var cantArgResolved = new Queue <string>();

            // 値解決の状況を記録するための辞書を用意する
            // *後続の処理では、あるオプションの値の解決に成功する都度、
            // この辞書の当該オプションのエントリーを検索して
            // その値であるリストにオプションの値を追加していく
            var ctx = new Dictionary <IOption <T>, List <string> >();

            foreach (var o in cl.Options)
            {
                ctx.Add(o, new List <string>());
            }

            // 解決待ちキューが空になるまでループ
            while (toArgResolve.Count > 0)
            {
                // 解決待ちキューの先頭から値を1つ取得(削除)
                var former = toArgResolve.Dequeue();
                // 解決待ちキューの先頭から値を1つ取得(非・削除)
                var latter = toArgResolve.Count == 0
                                                         ? string.Empty : toArgResolve.Peek();

                // 値解決を試みる
                var result = ResolveOptionsWithArguments(former, latter, ctx, vo);
                // 解決の成否をチェック
                if (result)
                {
                    // 成功の場合
                    // 値解決状況を記録する辞書からオプション定義を検索
                    var opt = ctx.First(a => HaveSameName(a.Key, former));

                    // オプションがそれ自体の引数をとるものかどうかチェック
                    if (opt.Key.HasArgument)
                    {
                        // 引数をとるものの場合
                        // 解決した値を辞書エントリーの値に追加
                        opt.Value.Add(latter);
                        // さらに解決待ちキューから値を削除
                        toArgResolve.Dequeue();
                    }
                    else
                    {
                        // 引数をとるものでない場合
                        // 解決した値を辞書エントリーの値にダミー値を追加
                        opt.Value.Add(string.Empty);
                    }
                }
                else
                {
                    // 失敗の場合
                    // 解決不可キューに値を追加
                    cantArgResolved.Enqueue(former);
                }
            }

            // 2. アプリケーション構成ファイルの処理

            // アプリケーション構成ファイルの設定情報に基づきループ
            foreach (var item in settings)
            {
                // 値解決を試みる
                var result = ResolveOptionsWithAppSettings(item.Key, item.Value, ctx, vo);
                // 成否をチェック
                if (result)
                {
                    // 成功の場合
                    // 値解決状況を記録する辞書からオプション定義を検索
                    var opt = ctx.First(a => a.Key.SettingName.Equals(item.Key));
                    if (opt.Key.HasArgument)
                    {
                        // 引数をとるものの場合
                        // 解決した値を辞書エントリーの値に追加
                        opt.Value.Add(settings[item.Key]);
                    }
                    else
                    {
                        // 引数をとるものでない場合
                        // 解決した値を辞書エントリーの値にダミー値を追加
                        var upper = item.Value.ToUpper();
                        if (upper.Equals("FALSE") || upper.Equals("NO") ||
                            upper.Equals("0") || upper.Equals("F") || upper.Equals("N"))
                        {
                            opt.Value.Add(false.ToString());
                        }
                        else
                        {
                            opt.Value.Add(true.ToString());
                        }
                    }
                }
            }

            // 3. コマンドライン引数の処理(後段階)

            // 解決不可キューの内容を「残りの引数」としてデリゲートに渡す
            cl.SetterDelegate(vo, cantArgResolved);

            // 4. 必死オプションのチェック

            // 必須にもかかわらず一連の処理で解決のできていないオプションを検索
            var missed = ctx.Where(kv => kv.Key.Required && kv.Value.Count() == 0)
                         .Select(kv => kv.Key).FirstOrDefault();

            if (missed != null)
            {
                // 該当するものが1件でもあった場合は例外をスローする
                throw MakeParseException(
                          ParseExceptionCategory.RequiredOptionNotFound,
                          missed, null);
            }
        }