ParameterSetをうまいこと設定して柔軟なFunctionを作ろう

例えばだ
スクリプトではなくシェルでFunctionを実行する際はパラメータ名を省略したいことはままあるのでPosition指定したい
さらにだ、必須パラメータが2つあって片方はパイプでも受け付けたりするとしよう
こんな感じで使いたいとする

PS> Func A B
PS> A | Func B

こうな、パラメータの一個目でAを受けたときはBは二個目
でもAをパイプで受けたときはBを一個目にしたい
こういうことがあるだろう
あるんだよ
僕はよくある

じゃあまずは

PS> Func A B

の場合でFunctionを定義してみましょう

function Test-ParameterSet
{
    param
    (
        [parameter(Mandatory,Position=0)]
        [int] $n,
        [parameter(Mandatory,Position=1)]
        [string] $s
    )
    process
    {
        return $s -f $n
    }
}
PS> Test-ParameterSet 1 '羊が{0}匹'
羊が1匹

はい
うまくできましたね
じゃあ次は

PS> A | Func B

の場合

function Test-ParameterSet
{
    param
    (
        [parameter(Mandatory,ValueFromPipeline)]
        [int] $n,
        [parameter(Mandatory,Position=0)]
        [string] $s
    )
    process
    {
        return $s -f $n
    }
}
PS> 1..3 | Test-ParameterSet '羊が{0}匹'
羊が1匹
羊が2匹
羊が3匹

はい、いい感じです

で、だ
これを組み合わせたいわけですよね、やってみましょう
最初のパターンはparamというParameterSet
二つ目のパターンはpipeというParameterSetにします

function Test-ParameterSet
{
    param
    (
        [parameter(Mandatory,ValueFromPipeline,ParameterSetName='pipe')]
        [parameter(Mandatory,Position=0,ParameterSetName='param')]
        [int] $n,
        [parameter(Mandatory,Position=0,ParameterSetName='pipe')]
        [parameter(Mandatory,Position=1,ParameterSetName='param')]
        [string] $s
    )
    process
    {
        return $s -f $n
    }
}

どうでしょう
実は一個のパラメータに対してparameter()をいくつもくっつけられるんですね
こうすることで状況に応じてParameterSetが変わるパラメータが作れるんですよ
さて

PS> 1..3 | Test-ParameterSet '羊が{0}匹'
羊が1匹
羊が2匹
羊が3匹

パイプはうまくいってます
パラメータでも渡してみましょう

PS> Test-ParameterSet 1 '羊が{0}匹'
Test-ParameterSet : 指定された名前のパラメーターを使用してパラメーター セットを解決できません。
発生場所 行:1 文字:1
+ Test-ParameterSet 1 '羊が{0}匹'
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Test-ParameterSet]、ParameterBindingException
    + FullyQualifiedErrorId : AmbiguousParameterSet,Test-ParameterSet

ややや、失敗しました
ややや、とか言ったけど実は想定内です
これはPowerShellの強力すぎる暗黙の型変換が裏目に出たパターンなんですね
最初のパラメータの1intだかstringだかわかんなくなってんです
はい困った、と思うじゃん?

実はこんなふうにParameterSetが解決出来ない場合につかうParameterSetのデフォルトを指定しとけるんですね
その名もDefaultParameterSetNameです、まんまだ
CmdletBinding()の中で定義します

function Test-ParameterSet
{
    [CmdletBinding(DefaultParameterSetName='param')]
    param
    (
        [parameter(Mandatory,ValueFromPipeline,ParameterSetName='pipe')]
        [parameter(Mandatory,Position=0,ParameterSetName='param')]
        [int] $n,
        [parameter(Mandatory,Position=0,ParameterSetName='pipe')]
        [parameter(Mandatory,Position=1,ParameterSetName='param')]
        [string] $s
    )
    process
    {
        return $s -f $n
    }
}

はい
ではもっかい実行してみましょう

PS> 1..3 | Test-ParameterSet '羊が{0}匹'
羊が1匹
羊が2匹
羊が3匹

PS> Test-ParameterSet 1 '羊が{0}匹'
羊が1匹

できた
ヨカッタネ

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中