お布団宇宙ねこ

にゃーん

optparse-applicativeを使ってCUIツールを作る

Haskellで簡単でもいいから何かツール作りたいなあと思ってシュッと作れそうなCUIツールを作ったので、作るにあたって利用したライブラリoptparse-applicativeの紹介をします。

はじめに

今回CUIツールを作る上で基本となるオプションパーサの部分にライブラリを使いました(というよりそこにしか使いませんでした)。オプションパーサのライブラリはこちらを見つつ、その後optparse-applicativeoptparse-simpleoptparse-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型を定義してparseHelloparseByeを実装しています。このパーサ関数にはコマンドが受け取る引数やヘルプで表示したい情報などを設定できます。

次にそれらのパーサ関数をまとめるパーサを用意します。ここでは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ツールを作れるのでした。
自分が実際に作ったものはこちらに置いてあります。

github.com

参考文献