Haskell: Turtle: анализатор командной строки
Я пытался создать парсер командной строки с Turtle, ничего особенного: https://github.com/Tyrn/go-procr
#!/usr/bin/env stack
{-# LANGUAGE OverloadedStrings #-}
module Main where
import Turtle
import Prelude hiding (FilePath)
parserSwitch :: Parser (Bool, Bool)
parserSwitch = (,) <$> switch "verbose" 'v' "Unless verbose, just progress bar is shown"
<*> switch "filetitle" 'f' "Use file name for title tag"
parserArg :: Parser (FilePath, FilePath)
parserArg = (,) <$> argPath "src" "Source directory"
<*> argPath "dst" "Destination directory"
main :: IO ()
main = do
(verbose, filetitle) <- options "Flags" parserSwitch
echo (format ("verbose: "%w) verbose)
echo (format ("filetitle: "%w) filetitle)
(src, dst) <- options "Args" parserArg
echo (format ("src: "%fp) src)
echo (format ("dst: "%fp) dst)
Требуются три вида аргументов: логические флаги; параметры, текст и целое число; позиционные аргументы. Пока что я застрял в логических флагах и позиционных аргументах. К сожалению, примеры кажутся слишком простыми даже для этого.
Действительно ли мне нужно создавать отдельные парсеры для разных типов опций (мне не удалось удовлетворить синтаксис одним парсером)?
В любом случае, это не сработает.
Я не могу понять, каким должен быть мой следующий шаг.
1 ответ
Ваш первый шаг - иметь что-то, где вы сможете легко хранить и извлекать ваши параметры:
data Settings = Settings
{ settingsVerbose :: Bool
, settingsFileTitle :: Bool
, settingsSource :: FilePath
, settingsDestination :: FilePath
}
После этого вы пишете парсеры для ваших опций. Чтобы прояснить ситуацию, давайте сначала будем немного многословны:
verboseParser :: Parser Bool
verboseParser = switch "verbose" 'v' "Be more verbose"
fileTitleParser :: Parser Bool
fileTitleParser = switch "filetitle" 'f' "..."
sourceParser :: Parser FilePath
sourceParser = argPath "src" "Source directory"
destinationParser :: Parser FilePath
destinationParser = argPath "dst" "Destination directory"
поскольку Parser
это пример Applicative
затем мы можем объединить все опции в одном парсере:
settingsParser :: Parser Settings
settingsParser =
Settings <$> verboseParser
<*> fileTitleParser
<*> sourceParser
<*> destinationParser
Мы объединили все четыре парсера в один парсер, аналогично комбинации через (,)
, Теперь мы можем разобрать варианты с помощью одного вызова options
, В конце концов, либо все аргументы верны, либо мы должны предоставить пользователю правильное использование:
main = do
s <- options "Description of your program" settingsParser
echo (format ("verbose: "%w) (settingsVerbose s))
echo (format ("filetitle: "%w) (settingsFileTitle s))
echo (format ("src: "%fp) (settingsSource s))
echo (format ("dst: "%fp) (settingsDestination s))
Вы, вероятно, хотите использовать более короткие имена, и, возможно, написать парсеры в settingsParser
:
data Settings = Settings
{ sVerbose :: Bool
, sFileTitle :: Bool
, sSource :: FilePath
, sDestination :: FilePath
}
settingsP :: Parser Settings
settingsP =
Settings <$> switch "verbose" 'v' "Be more verbose"
<*> switch "filetitle" 'f' "..."
<*> argPath "src" "Source directory"
<*> argPath "dest" "Destination directory"
description :: Description
description = "Description of your program"
main = do
(Settings verbose filetitle source dest) <- options description settingsP
...