社内SEの話

日々起きたことの記録用

Powershellでdecoratorをさせる

↓プログラミングで副業を考えたらこちら↓

こんにちは、はじめまして。めじろです

最近はPythonPowershellしかコードを書いていません。
特にPowershellの裾の広さに驚きつつ、業務系ではPowershellをメインに使っています。
逆にプライベートではモダンな開発ができるPythonしか書いていません。
そこでPythonでできるけどPowershellでできない事が度々発生します。Powershellもモダンではありますが・・・

タイトルにある通りデコレーターをPowershellで書くならという事例になります。

function Decorate-Function {
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$true)]
        [string]$ScriptBlock
    )
   
    begin {
        write-host "begin decoration"
    }
   
    process {
        & ([scriptblock]::Create($ScriptBlock))
    }
   
    end {
        write-host "end decoration"
    }
}


function func(){
    write-host "main function"
}

Decorate-Function -ScriptBlock func

お急ぎの方はこれを丸々コピペすればいいと思います。
あとはfuncを変えたり、デコレーションする部分を変更するだけで使えます。

その1 実行させる関数を作る

function func(){
    write-host "main function"
}

この部分は適当に作ります。
特別な記述も無いので普段どおり関数を作成すれば問題ありません。

その2 デコレーション関数を作る

CmdletBinding()

CmdletBinding()とは
docs.microsoft.com

デコレーションさせる大枠をこの機能を使います。
元はパイプをさせて使う関数なのですが、デコレーターと同じような動きなので、こちらをフレームとして使います

function Decorate-Function {
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$true)]
    )
   
    begin {

    }
   
    process {

    }
   
    end {

    }
}

[parameter(Mandatory=$true)]

[parameter(Mandatory=$true)]

これはパラメータは必須ですを宣言しています。 これにより、メイン関数の受け取りをミスを防ぎます

[string]$ScriptBlock

 param (
        [parameter(Mandatory=$true)]
        [string]$ScriptBlock
    )

引数をパラメータとして受け取ります。
引数にしてしまうと、メイン関数を実行してしまうので引数化はできません。
またメイン関数は文字列として受け取ります。 理由はPowershellの使用で関数を渡すと、文字列として扱われます。そのため関数として実行しようとするとエラーが発生してしまいます。
その回避策として文字列として受け渡しさせます。

& ([scriptblock]::Create($ScriptBlock))

scriptblockとは
docs.microsoft.com パイプで使用させる事を目的とした、非常にPowershellらしい機能です。

process {
        & ([scriptblock]::Create($ScriptBlock))
    }

&() はscriptblockを使うためのものなのでミスではありません。

::Create()で()内にあるものをコマンド化して実行可能にさせます。
引数の文字列をコマンドして実行させます。

Decorate-Function -ScriptBlock func

デコレーターを呼び出しパラメーターで実行したい関数を指定すると実行される関数に影響されないプログラムが実行されます。

場面

これが割りと便利で、ログの吐き出しや、実行中の関数名の表示など、作り方によって便利に使えます。 ただPythonの様によりモダンな形にはできなかったので、そのへんは今後の開発に期待かなーと

@decorator
def func(){
  print("Hello decorator")
}

Pythonならこんな形になるから使いやすい。