All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kynthus.hatalib.argparse.syntax.ParserSyntax1.scala Maven / Gradle / Ivy

The newest version!
package org.kynthus.hatalib.argparse.syntax

import org.kynthus.hatalib.argparse.concept._
import org.kynthus.hatalib.argparse.syntax.ParserSyntax.{ChildrenParserOps, ConfigParserOps, ElementParserOps, ParentParserOps, UnitParserOps}
import org.kynthus.hatalib.core.concept.{ResultCategory, Run}
import scalaz.syntax.bind.ToBindOps
import scalaz.{@@, Bind, \/, ~~>}
import scopt.OParser

import scala.language.{higherKinds, implicitConversions}

/**
 * 各種パーサ構築のためのメソッド拡張用クラスの第2候補です。
 *
 * @author Kynthus Auoeau
 * @since 1.0.0
 * @version 1.0.0
 */
private trait ParserSyntax1 extends Any {

  /**
   * ラップした型に対して、新しい型に対応したオプションを追加するメソッドを付与するクラスへの暗黙変換です。
   *
   * @param derived     構築中のパーサを保持する値
   * @param runCategory ラップする型を決定するマーカー
   * @param bind        平坦化変換が可能なことを保証する
   * @tparam Derived  構築中のパーサを保持する型
   * @tparam Category 型パラメータを持ち、[[scalaz.Bind]]の特性を持つ型
   * @tparam Input    現在値の型
   * @tparam Instance 各オプションの初期値を持つ型
   * @return ラップした型に対して、新しい型に対応したオプションを追加するメソッドを付与するクラスのインスタンス
   * @author Kynthus Auoeau
   * @since 1.0.0
   * @version 1.0.0
   */
  implicit final def CategoryElementParserOps[
    Derived,
    Category[_],
    Input,
    Instance
  ](derived: => Category[Derived @@ (Input @@ Instance)])
   (
     implicit
     runCategory: ResultCategory[Category] @@ Run.type,
     bind: Bind[Category]
   ): ParserSyntax1.CategoryElementParserOps[
    Derived,
    Category,
    Input,
    Instance
  ] = ParserSyntax1.CategoryElementParserOps(() => derived)

  /**
   * ラップした型に対して、型を持たないオプションを追加するメソッドを付与するクラスへの暗黙変換です。
   *
   * @param derived     構築中のパーサを保持する値
   * @param runCategory ラップする型を決定するマーカー
   * @param bind        平坦化変換が可能なことを保証する
   * @tparam Derived  構築中のパーサを保持する型
   * @tparam Category 型パラメータを持ち、[[scalaz.Bind]]の特性を持つ型
   * @tparam Input    現在値の型
   * @tparam Instance 各オプションの初期値を持つ型
   * @return ラップした型に対して、型を持たないオプションを追加するメソッドを付与するクラスのインスタンス
   * @author Kynthus Auoeau
   * @since 1.0.0
   * @version 1.0.0
   */
  implicit final def CategoryUnitParserOps[
    Derived,
    Category[_],
    Input,
    Instance
  ](derived: => Category[Derived @@ (Input @@ Instance)])
   (
     implicit
     runCategory: ResultCategory[Category] @@ Run.type,
     bind: Bind[Category]
   ): ParserSyntax1.CategoryUnitParserOps[
    Derived,
    Category,
    Input,
    Instance
  ] = ParserSyntax1.CategoryUnitParserOps(() => derived)

  /**
   * ラップした型に対して、オプションに対する詳細設定を行うメソッドを付与するクラスへの暗黙変換です。
   *
   * @param derived     構築中のパーサを保持する値
   * @param runCategory ラップする型を決定するマーカー
   * @param bind        平坦化変換が可能なことを保証する
   * @tparam Derived  構築中のパーサを保持する型
   * @tparam Category 型パラメータを持ち、[[scalaz.Bind]]の特性を持つ型
   * @tparam Input    現在値の型
   * @tparam Instance 各オプションの初期値を持つ型
   * @return ラップした型に対して、オプションに対する詳細設定を行うメソッドを付与するクラスのインスタンス
   * @author Kynthus Auoeau
   * @since 1.0.0
   * @version 1.0.0
   */
  implicit final def CategoryConfigParserOps[
    Derived,
    Category[_],
    Input,
    Instance
  ](derived: => Category[Derived @@ (Input @@ Instance)])
   (
     implicit
     runCategory: ResultCategory[Category] @@ Run.type,
     bind: Bind[Category]
   ): ParserSyntax1.CategoryConfigParserOps[
    Derived,
    Category,
    Input,
    Instance
  ] = ParserSyntax1.CategoryConfigParserOps(() => derived)

  /**
   * ラップした型に対して、子パーサへの分岐を行うメソッドを付与するクラスへの暗黙変換です。
   *
   * @param derived     構築中のパーサを保持する値
   * @param runCategory ラップする型を決定するマーカー
   * @param bind        平坦化変換が可能なことを保証する
   * @tparam Derived  構築中のパーサを保持する型
   * @tparam Category 型パラメータを持ち、[[scalaz.Bind]]の特性を持つ型
   * @tparam Input    現在値の型
   * @tparam Instance 各オプションの初期値を持つ型
   * @return ラップした型に対して、子パーサへの分岐を行うメソッドを付与するクラスのインスタンス
   * @author Kynthus Auoeau
   * @since 1.0.0
   * @version 1.0.0
   */
  implicit final def CategoryChildrenParserOps[
    Derived,
    Category[_],
    Input,
    Instance
  ](derived: => Category[Derived @@ (Input @@ Instance)])
   (
     implicit
     runCategory: ResultCategory[Category] @@ Run.type,
     bind: Bind[Category]
   ): ParserSyntax1.CategoryChildrenParserOps[
    Derived,
    Category,
    Input,
    Instance
  ] = ParserSyntax1.CategoryChildrenParserOps(() => derived)

  /**
   * ラップした型に対して、親パーサへ合流を行うメソッドを付与するクラスへの暗黙変換です。
   *
   * @param derived     構築中のパーサを保持する値
   * @param runCategory ラップする型を決定するマーカー
   * @param bind        平坦化変換が可能なことを保証する
   * @tparam Derived  構築中のパーサを保持する型
   * @tparam Category 型パラメータを持ち、[[scalaz.Bind]]の特性を持つ型
   * @tparam Input    現在値の型
   * @tparam Instance 各オプションの初期値を持つ型
   * @return ラップした型に対して、親パーサへ合流を行うメソッドを付与するクラスのインスタンス
   * @author Kynthus Auoeau
   * @since 1.0.0
   * @version 1.0.0
   */
  implicit final def CategoryParentParserOps[
    Derived,
    Category[_],
    Input,
    Instance
  ](derived: => Category[Derived @@ (Input @@ Instance)])
   (
     implicit
     runCategory: ResultCategory[Category] @@ Run.type,
     bind: Bind[Category]
   ): ParserSyntax1.CategoryParentParserOps[
    Derived,
    Category,
    Input,
    Instance
  ] = ParserSyntax1.CategoryParentParserOps(() => derived)

}

/**
 * 各種パーサ構築のためのメソッド拡張用クラスの第2候補を内部的に定義します。
 *
 * @author Kynthus Auoeau
 * @since 1.0.0
 * @version 1.0.0
 */
private object ParserSyntax1 extends AnyRef {

  /**
   * ラップした型に対して、新しい型に対応したオプションを追加するメソッドを付与するクラスです。
   *
   * @constructor 新しい型に対応したオプションを追加する拡張メソッド使用時に暗黙のうちに呼び出されます。
   * @param derived 構築中のパーサを保持する値
   * @tparam Derived  構築中のパーサを保持する型
   * @tparam Category 型パラメータを持ち、[[scalaz.Bind]]の特性を持つ型
   * @tparam Input    現在値の型
   * @tparam Instance 各オプションの初期値を持つ型
   * @author Kynthus Auoeau
   * @since 1.0.0
   * @version 1.0.0
   */
  private[syntax] final case class CategoryElementParserOps[
    Derived,
    Category[_],
    Input,
    Instance
  ](derived: () => Category[Derived @@ (Input @@ Instance)]) extends AnyRef {

    /**
     * パーサに設定したオプションをまとめて追加します。
     *
     * @param parser      追加するオプション
     * @param runCategory ラップする型を決定するマーカー
     * @param bind        平坦化変換が可能なことを保証する
     * @param base        オプションを追加できることを保証する
     * @tparam NewInput 新しい現在値の型
     * @tparam Output   オプションをパーサへ追加した後の型
     * @return 現在の型を更新し、オプションを追加した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def parser[NewInput, Output]
    (parser: OParser[NewInput, Instance])
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ElementParser.Aux[
        Derived @@ (Input @@ Instance),
        NewInput,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.parser(parser))

    /**
     * [[scala.Unit]]型を新たな現在値の型とし、単独の位置引数を追加します。
     *
     * @param name 位置引数名
     * @param base オプションを追加できることを保証する
     * @tparam Output オプションをパーサへ追加した後の型
     * @return 現在の型を[[scala.Unit]]へ更新し、位置引数を追加した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def arg[Output]
    (name: String)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ElementParser.Aux[
        Derived @@ (Input @@ Instance),
        Unit,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.arg(name))

    /**
     * クラス情報をもとに新しい現在値の型へ更新し、単独の位置引数を追加します。
     *
     * @param name    位置引数名
     * @param element 新しい現在値の型のクラス情報
     * @param base    オプションを追加できることを保証する
     * @tparam NewInput 新しい現在値の型
     * @tparam Output   オプションをパーサへ追加した後の型
     * @return 現在の型を更新し、位置引数を追加した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def arg[NewInput, Output]
    (name: String, element: => Class[NewInput])
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ElementParser.Aux[
        Derived @@ (Input @@ Instance),
        NewInput,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.arg(name, element))

    /**
     * 関数の戻り値をもとに新しい現在値の型へ更新し、単独の位置引数を追加します。
     *
     * @param name    位置引数名
     * @param element 新しい現在値を返す処理
     * @param base    オプションを追加できることを保証する
     * @tparam NewInput 新しい現在値の型
     * @tparam Output   オプションをパーサへ追加した後の型
     * @return 現在の型を更新し、位置引数を追加した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def arg[NewInput, Output]
    (name: String, element: Instance => NewInput)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ElementParser.Aux[
        Derived @@ (Input @@ Instance),
        NewInput,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.arg(name, element))

    /**
     * [[scala.Unit]]型を新たな現在値の型とし、単独のオプション付き引数を追加します。
     *
     * @param name オプション名
     * @param base オプションを追加できることを保証する
     * @tparam Output オプションをパーサへ追加した後の型
     * @return 現在の型を[[scala.Unit]]へ更新し、オプション付き引数を追加した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def opt[Output]
    (name: String)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ElementParser.Aux[
        Derived @@ (Input @@ Instance),
        Unit,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.opt(name))

    /**
     * クラス情報をもとに新しい現在値の型へ更新し、単独のオプション付き引数を追加します。
     *
     * @param name    オプション名
     * @param element 新しい現在値の型のクラス情報
     * @param base    オプションを追加できることを保証する
     * @tparam NewInput 新しい現在値の型
     * @tparam Output   オプションをパーサへ追加した後の型
     * @return 現在の型を更新し、オプション付き引数を追加した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def opt[NewInput, Output]
    (name: String, element: => Class[NewInput])
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ElementParser.Aux[
        Derived @@ (Input @@ Instance),
        NewInput,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.opt(name, element))

    /**
     * 関数の戻り値をもとに新しい現在値の型へ更新し、単独のオプション付き引数を追加します。
     *
     * @param name    オプション名
     * @param element 新しい現在値を返す処理
     * @param base    オプションを追加できることを保証する
     * @tparam NewInput 新しい現在値の型
     * @tparam Output   オプションをパーサへ追加した後の型
     * @return 現在の型を更新し、オプション付き引数を追加した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def opt[NewInput, Output]
    (name: String, element: Instance => NewInput)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ElementParser.Aux[
        Derived @@ (Input @@ Instance),
        NewInput,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.opt(name, element))

  }

  /**
   * ラップした型に対して、型を持たないオプションを追加するメソッドを付与するクラスです。
   *
   * @constructor 型を持たないオプションを追加する拡張メソッド使用時に暗黙のうちに呼び出されます。
   * @param derived 構築中のパーサを保持する値
   * @tparam Derived  構築中のパーサを保持する型
   * @tparam Category 型パラメータを持ち、[[scalaz.Bind]]の特性を持つ型
   * @tparam Input    現在値の型
   * @tparam Instance 各オプションの初期値を持つ型
   * @author Kynthus Auoeau
   * @since 1.0.0
   * @version 1.0.0
   */
  private[syntax] final case class CategoryUnitParserOps[
    Derived,
    Category[_],
    Input,
    Instance
  ](derived: () => Category[Derived @@ (Input @@ Instance)]) extends AnyRef {

    /**
     * プログラム名を設定します。
     *
     * @param name プログラム名
     * @param base オプションを追加できることを保証する
     * @tparam Output オプションをパーサへ追加した後の型
     * @return プログラム名を設定した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def programName[Output]
    (name: String)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: UnitParser.Aux[
        Derived @@ (Input @@ Instance),
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.programName(name))

    /**
     * ヘッダメッセージを設定します。
     *
     * @param message ヘッダメッセージ
     * @param base    オプションを追加できることを保証する
     * @tparam Output オプションをパーサへ追加した後の型
     * @return ヘッダメッセージを追加した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def head[Output]
    (message: String*)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: UnitParser.Aux[
        Derived @@ (Input @@ Instance),
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.head(message: _*))

    /**
     * サブコマンドを追加します。
     *
     * @param name サブコマンド名
     * @param base オプションを追加できることを保証する
     * @tparam Output オプションをパーサへ追加した後の型
     * @return サブコマンドを追加した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def cmd[Output]
    (name: String)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: UnitParser.Aux[
        Derived @@ (Input @@ Instance),
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.cmd(name))

    /**
     * ヘルプ表示用のオプションを追加します。
     *
     * @param name ヘルプ表示用のオプション名
     * @param base オプションを追加できることを保証する
     * @tparam Output オプションをパーサへ追加した後の型
     * @return ヘルプ表示用のオプションを追加した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def help[Output]
    (name: String)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: UnitParser.Aux[
        Derived @@ (Input @@ Instance),
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.help(name))

    /**
     * バージョン表示用のオプションを追加します。
     *
     * @param name バージョン表示用のオプション名
     * @param base オプションを追加できることを保証する
     * @tparam Output オプションをパーサへ追加した後の型
     * @return バージョン表示用のオプションを追加した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def version[Output]
    (name: String)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: UnitParser.Aux[
        Derived @@ (Input @@ Instance),
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.version(name))

    /**
     * コマンドの使用方法として表示されるメッセージを追加します。
     *
     * @param message コマンド使用方法のメッセージ
     * @param base    オプションを追加できることを保証する
     * @tparam Output オプションをパーサへ追加した後の型
     * @return コマンドの使用方法を追加した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def note[Output]
    (message: String)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: UnitParser.Aux[
        Derived @@ (Input @@ Instance),
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.note(message))

    /**
     * 実際にコマンドから渡されたオプション値を検証します。
     *
     * コマンドライン引数の解析後に実行され、インスタンスが持つフィールド値を見て判断を行います。
     * 正常値であれば成功を示す型を、異常値であれば失敗を示す型を返します。
     *
     * 今後予想されるScalaz 7.3.x系への移行に備え、
     * いったん[[scalaz.\/]]へ変換後に、その後[[scala.Either]]へ変換します。
     *
     * @param checker       フィールド値に対する、正常・異常の判定処理
     * @param base          オプションを追加できることを保証する
     * @param toDisjunction 成功・失敗を表現可能な型から[[scalaz.\/]]へ変換できることを保証する
     * @param toEither      [[scalaz.\/]]から[[scala.Either]]へ変換できることを保証する
     * @tparam UnusedRight    成功を表現する型が持つ右側の型([[scala.Unit]]への変換により破棄)
     * @tparam UnusedCategory 2つの型パラメータを持ち、成功・失敗を表現可能な型
     * @tparam Output         オプションをパーサへ追加した後の型
     * @return 検証処理を設定した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def checkConfig[UnusedRight, UnusedCategory[_, _], Output]
    (checker: Instance => UnusedCategory[String, UnusedRight])
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: UnitParser.Aux[
        Derived @@ (Input @@ Instance),
        Instance,
        Category[Output]
      ],
      toDisjunction: UnusedCategory ~~> \/,
      toEither: \/ ~~> Either
    ): Category[Output] = this.derived() >>= (_.checkConfig(checker))

  }

  /**
   * ラップした型に対して、オプションに対する詳細設定を行うメソッドを付与するクラスです。
   *
   * @constructor オプションに対する詳細設定を行う拡張メソッド使用時に暗黙のうちに呼び出されます。
   * @param derived 構築中のパーサを保持する値
   * @tparam Derived  構築中のパーサを保持する型
   * @tparam Category 型パラメータを持ち、[[scalaz.Bind]]の特性を持つ型
   * @tparam Input    現在値の型
   * @tparam Instance 各オプションの初期値を持つ型
   * @author Kynthus Auoeau
   * @since 1.0.0
   * @version 1.0.0
   */
  private[syntax] final case class CategoryConfigParserOps[
    Derived,
    Category[_],
    Input,
    Instance
  ](derived: () => Category[Derived @@ (Input @@ Instance)]) extends AnyRef {

    /**
     * オプションに対して別名を設定します。
     *
     * @param name オプションの別名
     * @param base 詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return 別名を設定した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def abbr[Output]
    (name: String)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.abbr(name))

    /**
     * オプションが指定された際に実行する処理のうち、固定値の設定用に使用します。
     *
     * @param function 固定値を設定する処理
     * @param base     詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return 実行する処理を設定した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def set[Output]
    (function: Instance => Instance)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.set(function))

    /**
     * オプションが指定された際に実行する処理を設定します。
     *
     * @param function 実行する処理
     * @param base     詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return 実行する処理を設定した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def action[Output]
    (function: (Instance, Input) => Instance)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.action(function))

    /**
     * オプションの説明文を設定します。
     *
     * @param message オプションに対する説明文
     * @param base    詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return オプションの説明文を設定します。
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def text[Output]
    (message: String)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.text(message))

    /**
     * オプションに最低限必要な引数の数を設定します。
     *
     * @param occurs 最低限必要な引数の数
     * @param base   詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return 最低限必要な引数の数を設定した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def minOccurs[Output]
    (occurs: Int)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.minOccurs(occurs))

    /**
     * オプションに引数をいくつまで指定できるかを設定します。
     *
     * @param occurs 引数の最大数
     * @param base   詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return 引数の最大数を設定した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def maxOccurs[Output]
    (occurs: Int)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.maxOccurs(occurs))

    /**
     * オプションを必須扱いにします。
     *
     * @param base 詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return オプションを必須化した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def required[Output]
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.required)

    /**
     * オプションを任意(省略可能)にします。
     *
     * @param base 詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return オプションを任意化した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def optional[Output]
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.optional)

    /**
     * オプションに対して引数を無制限に指定できるようにします。
     *
     * @param base 詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return 引数の指定数を無制限とした結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def unbounded[Output]
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.unbounded)

    /**
     * オプションを隠しオプションにします。
     *
     * @param base 詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return 隠しオプション化した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def hidden[Output]
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.hidden)

    /**
     * オプションのキー名を設定します。
     *
     * @param name キー名
     * @param base 詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return キー名を設定した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def keyName[Output]
    (name: String)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.keyName(name))

    /**
     * オプションの値名を設定します。
     *
     * @param name 値名
     * @param base 詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return 値名を設定した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def valueName[Output]
    (name: String)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.valueName(name))

    /**
     * オプションのキー名と値名を設定します。
     *
     * @param keyName   キー名
     * @param valueName 値名
     * @param base      詳細設定が可能なことを保証する
     * @tparam Output オプションへ詳細設定を適用した後の型
     * @return キー名と値名を設定した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def keyValueName[Output]
    (keyName: String, valueName: String)
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.keyValueName(keyName, valueName))

    /**
     * 実際にコマンドから渡されたオプション値を検証します。
     *
     * コマンドライン引数の解析中に実行され、オプションに対する引数の値を判断します。
     * 正常値であれば成功を示す型を、異常値であれば失敗を示す型を返します。
     *
     * 今後予想されるScalaz 7.3.x系への移行に備え、
     * いったん[[scalaz.\/]]へ変換後に、その後[[scala.Either]]へ変換します。
     *
     * @param validator     検証処理
     * @param base          詳細設定が可能なことを保証する
     * @param toDisjunction 成功・失敗を表現可能な型から[[scalaz.\/]]へ変換できることを保証する
     * @param toEither      [[scalaz.\/]]から[[scala.Either]]へ変換できることを保証する
     * @tparam UnusedRight    成功を表現する型が持つ右側の型([[scala.Unit]]への変換により破棄)
     * @tparam UnusedCategory 2つの型パラメータを持ち、成功・失敗を表現可能な型
     * @tparam Output         オプションへ詳細設定を適用した後の型
     * @return 検証処理を設定した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def validate[UnusedRight, UnusedCategory[_, _], Output]
    (validator: Input => UnusedCategory[String, UnusedRight])
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ConfigParser.Aux[
        Derived @@ (Input @@ Instance),
        Input,
        Instance,
        Category[Output]
      ],
      toDisjunction: UnusedCategory ~~> \/,
      toEither: \/ ~~> Either
    ): Category[Output] = this.derived() >>= (_.validate(validator))

  }

  /**
   * ラップした型に対して、子パーサへの分岐を行うメソッドを付与するクラスです。
   *
   * @constructor 子パーサへの分岐を行う拡張メソッド使用時に暗黙のうちに呼び出されます。
   * @param derived 構築中のパーサを保持する値
   * @tparam Derived  構築中のパーサを保持する型
   * @tparam Category 型パラメータを持ち、[[scalaz.Bind]]の特性を持つ型
   * @tparam Input    現在値の型
   * @tparam Instance 各オプションの初期値を持つ型
   * @author Kynthus Auoeau
   * @since 1.0.0
   * @version 1.0.0
   */
  private[syntax] final case class CategoryChildrenParserOps[
    Derived,
    Category[_],
    Input,
    Instance
  ]
  (derived: () => Category[Derived @@ (Input @@ Instance)]) extends AnyRef {

    /**
     * 子パーサへ分岐した結果を返します。
     *
     * @param base 子パーサへ分岐可能なことを保証する
     * @tparam Output 子パーサへ分岐した後の型
     * @return 子パーサへ分岐した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def children[Output]
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ChildrenParser.Aux[
        Derived @@ (Input @@ Instance),
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.children)

  }

  /**
   * ラップした型に対して、親パーサへ合流を行うメソッドを付与するクラスです。
   *
   * @constructor 親パーサへ合流を行う拡張メソッド使用時に暗黙のうちに呼び出されます。
   * @param derived 構築中のパーサを保持する値
   * @tparam Derived  構築中のパーサを保持する型
   * @tparam Category 型パラメータを持ち、[[scalaz.Bind]]の特性を持つ型
   * @tparam Input    現在値の型
   * @tparam Instance 各オプションの初期値を持つ型
   * @author Kynthus Auoeau
   * @since 1.0.0
   * @version 1.0.0
   */
  private[syntax] final case class CategoryParentParserOps[
    Derived,
    Category[_],
    Input,
    Instance
  ](derived: () => Category[Derived @@ (Input @@ Instance)]) extends AnyRef {

    /**
     * 親パーサへ合流した結果を返します。
     *
     * @param base 親パーサへ合流可能なことを保証する
     * @tparam Output 親パーサへ合流した後の型
     * @return 親パーサへ合流した結果
     * @author Kynthus Auoeau
     * @since 1.0.0
     * @version 1.0.0
     */
    def parent[Output]
    (
      implicit
      runCategory: ResultCategory[Category] @@ Run.type,
      bind: Bind[Category],
      base: ParentParser.Aux[
        Derived @@ (Input @@ Instance),
        Category[Output]
      ]
    ): Category[Output] = this.derived() >>= (_.parent)

  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy