2013-06-30 24 views
7

Sto cercando una libreria che utilizzi una monade per astrarre il trambusto dell'argomentazione della riga di comando e della generazione di aiuto. Ho il seguente modello di utilizzo abbastanza ovvio in mente:Argomenti della riga di comando che leggono la libreria monad

main = do 
    portOrSocket <- Args.run $ do 
    mbSocket <- Args.read $ Args.Arg "s" "socket" "Description" 
    mbPort <- Args.read $ Args.Arg "p" "port" "Description" 
    case mbSocket of 
     Just socket -> return $ Right socket 
     Nothing -> case mbPort of 
     Just port -> return $ Left port 
     Nothing -> return $ Left defaultPort 
    ... 

Il codice di cui sopra ha tutte le informazioni necessarie per gestire l'analisi, la convalida e l'uso di generazione e IMO è abbastanza facile da comprendere. Sfortunatamente, dopo aver guardato attraverso l'hackage e aver controllato pacchetti come cmdargs, cmdlib, parseargs, ReadArgs, non ho trovato nulla da nessuna parte vicino a questo. Ma prima di immergermi nell'implementazione mi piacerebbe assicurarmi di non aver perso nulla. Quindi c'è una biblioteca che sfrutta un approccio simile al problema?

+8

Hai provato 'optparse-applicative'? –

+4

+1 per 'optparse-applicative'. È ottimo. – jtobin

+1

Sembra che sarebbe quasi impossibile generare messaggi di aiuto automatici, se i parametri dipendono dai valori di altri parametri. Questo è probabilmente il motivo per cui _optparse-applicative_ utilizza Applicative. –

risposta

8

È possibile utilizzare optparse-applicative. Il modello di uso più comune si presenta così (io sono solo copia e-incolla da una piccola utility che uso):

options :: Parser (String, String) 
options = (,) 
    <$> (strOption $ mconcat [ 
     short 'n', 
     long "node", 
     metavar "NODE", 
     value "127.0.0.1", 
     showDefaultWith id, 
     completer (bashCompleter "hostname"), 
     help "AMQP node to connect to" ]) 
    <*> (strOption $ mconcat [ 
     short 'q', 
     long "queue", 
     metavar "QUEUE", 
     value "1.0.0", 
     showDefaultWith id, 
     help "Queue to initialize" ]) 

main = do 
    (hostName, queue) <- 
     execParser $ info (helper <*> options) $ mconcat [ 
      fullDesc, 
      header "The Suns setup utility", 
      progDesc "Sets up an AMQP node", 
      footer "Report bugs to [email protected]" ] 
    ... 

Quando eseguo il programma compilato con -h, ottengo:

$ suns-admin -h 
The Suns setup utility 

Usage: suns-admin [-n|--node NODE] [-q|--queue QUEUE] 
    Sets up an AMQP node 

Available options: 
    -h,--help    Show this help text 
    -n,--node NODE   AMQP node to connect to (default: 127.0.0.1) 
    -q,--queue QUEUE   Queue to initialize (default: 1.0.0) 

Report bugs to [email protected] 

Questo ti dà un'idea di alcune eleganti opzioni che puoi giocare e il buon output che il programma genera.

2

Se qualcuno è interessato a risolvere il problema presentato nella questione utilizzando optparse-applicative, ecco come ho realizzato che:

import Options.Applicative 

getOptions :: Int -> IO (Either Int String) 
getOptions defaultPort = 
    execParser $ 
    info (helper <*> parser defaultPort) $ 
    fullDesc <> 
    progDesc "Run a content-db server on a socket or a port" <> 
    header "Run a content-db server" 

parser :: Int -> Parser (Either Int String) 
parser defaultPort = 
    portOrSocket <$> 
    (optional . strOption) 
     (short 's' <> 
     long "socket" <> 
     help "Socket") 
    <*> 
    option 
     (short 'p' <> 
     long "port" <> 
     help "Port" <> 
     value defaultPort) 
    where 
    portOrSocket (Just socket) _ = Right socket 
    portOrSocket _ port = Left port 

main = do 
    getOptions 43400 >>= \o -> case o of 
    Left port -> print port 
    Right socket -> print socket 
Problemi correlati