@hackage commander0.1.0.0

pattern matching against string based commands

Commander: A Haskell Library for parsing commands

This library aims to make it super easy to create and use nested commands with flags in the form of an object that is easy to traverse and run custom actions on, and easy to extend with handling for safe casting to values from their input strings.

As an example of usage (take a look in the examples folder for more) we can define commands as follows:

someCommands :: Command (IO ())
someCommands = commands $ do

    command "repeat" $ do

        help "Repeat a string n times"

        run $
            \(Value str :: Value "value to repeat" String)
             (Flag n :: Flag '["n"] "times to repeat" Int) ->
             sequence_ $ replicate n (putStrLn str)

    command "calculate" $ do

        help "perform calculations"

        command "add" $ do

            help "add two numbers"

            run $
                \(Value n1 :: Value "number 1" Int)
                 (Value n2 :: Value "number 2" Int)
                 (Flag verbose :: Flag '["v", "verbose"] "verbose mode" Bool) ->
                 if verbose
                    then putStrLn $ (show n1) ++ " + " ++ (show n2) ++ " = " ++ (show $ n1 + n2)
                    else putStrLn (show $ n1 + n2)

        command "multiply" $ do

            help "multiply two numbers"

            run $
                \(Value n1 :: Value "number 1" Int)
                 (Value n2 :: Value "number 2" Int) ->
                 putStrLn $ (show n1) ++ " x " ++ (show n2) ++ " = " ++ (show $ n1 * n2)

And this leads to someCommands being a nested record of type Command (IO ()) (where IO () corresponds to the output from the functions you provide). This record can then be traversed and interacted with.

The novelty of this approach (compared to others I have seen, which is a non exhaustive list!) is the use of the functions input parameter types to cast-from-string and inject the appropriate values into the function safely at runtime, as well as to generate documentation. This means that we only declare the flags and values each command requires in one place, and do not execute any of the output unless all parameters are fully satisfied. These functions are then safely hidden away inside an existential type, and so we don't need any other type level magic or handling to work with the output.

Installation

  1. Add this repository to your stack.yaml file under the packages folder, so we end up with something that looks a bit like:

    packages:
    - '.'
    - location:
       git: https://github.com/jsdw/hs-commander
       commit: abcdef123456789abcdef1234
    
  2. run stack install.

  3. import Commander into your library.

you can run the example code by running stack install :example1 && example1 assuming that the directory stack copies binaries to is present in your PATH.

Documentation

if you clone this repository locally somewhere, you can use stack haddock inside its folder in order to generate haddock documentation for it.

Disclaimer

This project is still under heavy development and could well change drastically!