optparse-applicativeを使ってCUIツールを作る
Haskellで簡単でもいいから何かツール作りたいなあと思ってシュッと作れそうなCUIツールを作ったので、作るにあたって利用したライブラリoptparse-applicativeの紹介をします。
はじめに
今回CUIツールを作る上で基本となるオプションパーサの部分にライブラリを使いました(というよりそこにしか使いませんでした)。オプションパーサのライブラリはこちらを見つつ、その後optparse-applicativeかoptparse-simpleかoptparse-genericに絞って、最終的に一番ドキュメントの量が多くコードの読みやすかったoptparse-applicativeを使っています。optparse-genericもよかったのですがサブコマンドの書き方がよくわからなくて断念してしまいました。
オプションパーサのライブラリを使ってますが、実はオプションは一つも実装していないのでどちらかと言うとサブコマンドを実装したい人向けの記事になります。
実装例
コマンド部分は以下のように簡単に作れます。
module Main where import Options.Applicative import Data.Semigroup ((<>)) data Command = Hello name | Bye name msg deriving (Show) parseHello :: Parser Command parseHello = Hello <$> argument str (metavar "[NAME]") parseBye :: Parser Command parseBye = Bye <$> argument str (metavar "[NAME]") <*> argument str (metavar "[MESSAGE]") withInfo :: Parser a -> String -> ParserInfo a withInfo opts desc = info (helper <*> opts) $ progDesc desc parseCommand :: Parser Command parseCommand = subparser $ command "hello" (parseHello `withInfo` "Say Hello") <> command "bye" (parseBye `withInfo` "Say Bye") parseInfo :: ParserInfo Command parseInfo = parseCommand `withInfo` "Greeting" execCommand :: IO () execCommand = execParser parseInfo >>= run where run cmd = case cmd of Hello n -> sayHello n Bye n m -> sayBye n m main :: IO () main = execCommand
まず、実装したいサブコマンドやオプションの型を定義してそれをParser型で包んだパーサ関数を定義します。ここではComannd
型を定義してparseHello
やparseBye
を実装しています。このパーサ関数にはコマンドが受け取る引数やヘルプで表示したい情報などを設定できます。
次にそれらのパーサ関数をまとめるパーサを用意します。ここではparseCommand
がそれにあたります。
あとはそれをexecParser関数に食わせることで入力された文字をいい感じにパースしてコマンドと引数に分解してくれます。
実行
デフォルトでヘルプオプションが付いてくるので、上のような実装だけでもいい感じのコマンドが作れてしまいます。
> stack runghc Main.hs -- --help Usage: Main.hs COMMAND Greeting Available options: -h,--help Show this help text Available commands: hello Say Hello bye Say Bye > stack runghc Main.hs -- hello --help Usage: Main.hs hello [NAME] Say Hello Available options: -h,--help Show this help text
まとめ
以上、optparse-applicativeを使うとお手軽にCUIツールを作れるのでした。
自分が実際に作ったものはこちらに置いてあります。