PowerShellで中くらいのものを書くときに考えたこと その1

体調不良などがあり、少しブログを書くのを中断してしまったが、また書いていきたいと思う。

今回はPowerShellの話。

今までPowerShellVSTS上のTaskで小さいものを書いていた程度で、特に文法とかコーディングの作法とかを考えずに書いていたが、ある程度の大きさのものを作成しようと思った場合、他人が読んだ場合や自分が半年後に読んだ場合でも、すぐに理解が追い付くようなものにした方がよいと思うのでその辺をどうするか考えたものを書こうと思う。

  1. IDEや環境面
  2. コーディング規約
  3. 外部ファイル化(外部のps1ファイルの関数呼び出し)
  4. スコープ
  5. テスト

IDEや環境面

小さいものを書くのであれば、IDEなどなくとも、メモ帳でもなんでもいいという気持ちだったが、ある程度の大きなものを扱う場合、関数の一覧を見たかったり、コード補完機能が欲しくなったりして結局最終的にVS CodePowerShell拡張機能を追加して開発することにした。
今回はWindows Powershellでの開発をしたかった(Mount-DiskImageなどisoファイルを扱ったりなどがあった)ので、Windows 8.1マシンだったが、下記リンクのWMF5.1を使って、Windows PowerShellのバージョンを5.1に上げておいた。
Installing Windows PowerShell | Microsoft Docs

なお、すべてを理解したわけではないが、Windows PowerShellPowerShell Coreは違うもので、.NET Frameworkと.NET Coreみたいな関係のように見える。
Installing PowerShell | Microsoft Docs
PowerShell CoreにはMount-DiskImageなどの関数がなく、なぜ動かないんだろう・・・?ということで小一時間調べたりした。

コーディング規約

どういう規約でもある程度まともに設定されていればいいと思いますが、基本的にモジュール単位、ファイル単位で統一されたものになっていることが大事だと考えています。
調べたことはこのあたり

すごくいろいろ調べてあって、すごい。全部読みきれなかったが、自分に必要そうな部分を読み取った。
PowerShell のコーディングスタイル - tech.guitarrapc.cóm
また、命名はこのあたり。本家なので、概要から全部読み直してもいい。
PowerShell で用いられる名前の習得 | Microsoft Docs
関数のドキュメントはこのあたり。VSCodeなどのIDEから便利に使えるようにするにはドキュメントも書いておきたいのでここも読んだ。
Windows PowerShell: Build a Better Function | Microsoft Docs


読み取ったのはこのあたり

  • 変数名
    • camelCaseなのかPascalCaseなのか
      • グローバルな変数かローカルな変数かで判断した
      • グローバルな変数はPascalCaseにした
      • ローカルな変数はcamelCaseにした
      • 関数宣言の引数はPascalCaseにした
  • 関数名
    • 今回作成したモジュールでは、すべてデフォルトのスコープ設定にした
    • camelCaseとかPascalCaseではなく、Verb-Nounという形式で書く
      • Verbに設定する単語はGet-Verbsコマンドの一覧から適切なものを利用する
  • 関数ドキュメント
    • 関数の中の先頭に書く

外部ファイル化(外部のps1ファイルの関数呼び出し)

外部ファイルを読みだす場合には、下記のように書いてファイルを読み込むようなコードを追加する

. '.\hoge.ps1'

ただ、上記の記述は実行するパスからの相対参照となるので、仮に↓のような構造にしていた場合、PowerShellコンソールからmain.test.ps1を呼び出して、main.test.ps1の中でmain.ps1を呼び出し、さらにmain.ps1の中で

. '.\hoge.ps1'

とした場合には、hoge.ps1が読み込めません、という意味のエラーメッセージが出力される。
root
 ┣src-dir
 ┃ ┣hoge.ps1
 ┃ ┗main.ps1
 ┗test-dir
   ┣hoge.test.ps1
   ┗main.test.ps1

test用のファイルを上記のように作っているとこういうことになるだけで、Pesterのようなテストツールでテスト用ファイルを自動生成する際にもプロダクトコードと同じ階層に出力されるので、特に問題は発生しないのかもしれない。ただ、もし上記のようなコードでも動くようにするには、関数の中で外部ファイルを相対パスで読み込むような形にする方法があるようだ。

function New-TestFunc ($paramArgs) {
    # ps1読込
    $scriptPath = $script:MyInvocation.MyCommand.Path
    $dirPath = Split-Path -Parent $scriptPath
    $rootPath = Split-Path -Parent $dirPath
    . "$rootPath\src-dir\hoge.ps1"

    # (以下略)
}

変数のスコープとテストについては、別日に書きます。