packages feed

optparse-declarative 0.4.2 → 0.4.3

raw patch · 7 files changed

+325/−320 lines, 7 files

Files

LICENSE view
@@ -1,20 +1,20 @@-Copyright (c) 2020 Kazuki Okamoto, 2015 Hideyuki Tanaka
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be included
-in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+Copyright (c) 2020 Kazuki Okamoto, 2015 Hideyuki Tanaka++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
README.md view
@@ -1,256 +1,256 @@-# optparse-declarative
-
-[![Hackage](https://matrix.hackage.haskell.org/api/v2/packages/optparse-declarative/badge)](http://hackage.haskell.org/package/optparse-declarative) [![GitHub Actions: test](https://github.com/tanakh/optparse-declarative/workflows/test/badge.svg)](https://github.com/tanakh/optparse-declarative/actions?query=workflow%3Atest) [![Join the chat at https://gitter.im/optparse-declarative/community](https://badges.gitter.im/optparse-declarative/community.svg)](https://gitter.im/optparse-declarative/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-
-`optparse-declarative` is a declarative and easy-to-use command-line option parser.
-
-# Install
-
-```bash
-$ cabal install optparse-declarative
-```
-
-# Usage
-
-## Writing a simple command
-
-First, you need to enable `DataKinds` extension. Then import `Options.Declarative` module.
-
-```hs
-{-# LANGUAGE DataKinds #-}
-import           Options.Declarative
-```
-
-Next, define command line options as a **type of the function**.
-For example, this is a simple greeting program with `-g` option that
-takes a message of type `String` and an unnamed command-line argument
-that specifies a name:
-
-```hs
-greet :: Flag "g" '["greet"] "STRING" "greeting message" (Def "Hello" String)
-      -> Arg "NAME" String
-      -> Cmd "Greeting command" ()
-greet msg name =
-    liftIO $ putStrLn $ get msg ++ ", " ++ get name ++ "!"
-```
-
-There are two types of options, `Flag` and `Arg`.
-`Flag` represents a named argument (e.g., `--greet "Hola"`), and `Arg` an unnamed argument (e.g., `John` of `greet --greet Hola John`).
-The last argument of `Flag` and `Arg` is the type of the value of the
-argument; in this example, they are both `String`.
-You can specify any type for the value as long as the type is an
-instance of `ArgRead` typeclass, in which the conversion function
-from `String` to the specified type is defined.
-`Options.Declarative` provides following instances of `ArgRead`
-typeclass.
-
-- Int
-- Integer
-- Bool
-- Double
-- String
-- (ArgRead a) => Maybe a
-
-Users can add a new instance of `ArgRead` to support any user-defined type.
-Please see Section "How to add a new instance of `ArgRead`" for details.
-
-If you wish to specify a default value for allowing users to omit a
-value, use the modifier `Def` with the default value as the second type argument (and the third type argument is the type of the value).
-You need to specify the default value in `String` instead of the final
-value of the target type; the string will be converted to the final
-value via `ArgRead` typeclass.
-
-In the example above, the variable `msg` has a very complex type (`Flag "g" '["greet"] "STRING" "greeting message" (Def "Hello" String)`).
-In order to get the value of the target type (in this case, that is `String`),
-you can use `get` function.
-
-The whole type of command is `Cmd`.
-`Cmd` is an instance of `MonadIO` and it has some extra information.
-
-Finally, you can run the whole program by `run_`.
-
-```hs
-main :: IO ()
-main = run_ greet
-```
-
-Here is an example session with the program shown above.
-
-```bash
-$ ghc simple.hs
-
-$ ./simple
-simple: not enough arguments
-Try 'simple --help' for more information.
-
-$ ./simple --help
-Usage: simple [OPTION...] NAME
-Options:
-  -g STRING  --greet=STRING  greeting message
-  -?         --help          display this help and exit
-
-$ ./simple World
-Hello, World!
-
-$ ./simple --greet=Goodbye World
-Goodbye, World!
-```
-
-Note that only the final option is used when multiple options of the
-same name are given. This behavior emulates the behavior of a naive
-program that uses GNU Getopt.
-
-```bash
-$ ./simple --greet=Hello --greet=Goodbye World
-Goodbye, World!
-```
-
-There is another way of interpreting multiple options of the same name.
-Suppose if you need to get multiple values from the same option.
-Say, you wish to get `["Hello", "Goodbye"]` from the command-line
-option `--greet=Hello --greeet=Goodbye`. Then, you can use
-the type `[]` to indicate that it accepts multiple values.
-The first line of the function `greet` in the example above
-would be changed as this:
-
-```hs
-greet :: Flag "g" '["greet"] "STRING" "greeting message" [String]
-```
-
-The value returned by `get` will be a value of type `[String]`.
-See the complete working example at `example/list.hs` for details.
-
-
-## Writing multiple subcommands
-
-You can write (nested) subcommands.
-You don't know what subcommands are? Imagine `git` command.
-`git` has subcommands such as `git add`, `git commit`, `git log`, etc.
-`git` has nested subcommands such as `git remote add`, `git remote rm`,
-etc.
-`optparse-declarative` provides an easy way to provide such possibly
-nested subcommands.
-
-Just group subcommands by `Group`, then you get a subcommand parser.
-Here is an example with two subcommands `greet` and `connect`:
-
-```hs
-{-# LANGUAGE DataKinds #-}
-
-import           Options.Declarative
-
-main :: IO ()
-main = run_ $
-    Group "Test program for library"
-    [ subCmd "greet"   greet
-    , subCmd "connect" connect
-    ]
-
-greet :: Flag "g" '["greet"] "STRING" "greeting message" (Def "Hello" String)
-      -> Flag "" '["decolate"] "" "decolate message" Bool
-      -> Arg "NAME" String
-      -> Cmd "Greeting command" ()
-greet msg deco name = do
-    let f x | get deco = "*** " ++ x ++ " ***"
-            | otherwise = x
-    liftIO $ putStrLn $ f $ get msg ++ ", " ++ get name ++ "!"
-
-connect :: Flag "h" '["host"] "HOST" "host name"   (Def "localhost" String)
-        -> Flag "p" '["port"] "PORT" "port number" (Def "8080"      Int   )
-        -> Cmd "Connect command" ()
-connect host port = do
-    let addr = get host ++ ":" ++ show (get port)
-    liftIO $ putStrLn $ "connect to " ++ addr
-```
-
-This is a sample session for the program above:
-
-```bash
-$ ./subcmd --help
-Usage: subcmd [OPTION...] <COMMAND> [ARGS...]
-Options:
-  -?  --help  display this help and exit
-
-Commands:
-  greet       Greeting command
-  port        Server command
-
-$ ./subcmd connect --port=1234
-connect to localhost:1234
-```
-
-If you wish to specify the program name or the version number,
-use `run` instead of `run_`. The first argument of `run` is
-a program name (of type `String`). The second argument is
-a version number (of type `Maybe String`).
-
-```hs
-main :: IO ()
-main = run "program_name" (Just "1.3.2") $
-    Group "Test program for library"
-    [ subCmd "greet"   greet
-    , subCmd "connect" connect
-    ]
-```
-
-For more examples, please see `example` directory.
-
-
-## Default options
-`optparse-declarative` provides a few default options.
-For example, `--help` is defined automatically so users do not have to
-write it by their own. If run with `run` and the version number,
-`--version` is defined automatically. Also, `--verbosity` option (`-v`
-for short) is defined by default.
-`getVerbosity` returns the verbosity level in `Int`.
-`-v` gives 1, `-vv` gives 2, `-vvv` gives 3.
-Alternatively, `--verbose=3` would yield 3.
-
-
-## How to add a new instance of `ArgRead`
-Users need to create an instance of `ArgRead` for supporting a new type
-for the command line argument. Here is the definition of class
-`ArgRead`.
-
-```hs
-class ArgRead a where
-    -- | Type of the argument
-    type Unwrap a :: *
-    type Unwrap a = a
-
-    -- | Get the argument's value
-    unwrap :: a -> Unwrap a
-    default unwrap :: a ~ Unwrap a => a -> Unwrap a
-    unwrap = id
-
-    -- | Argument parser
-    argRead :: [String] -> Maybe a
-    default argRead :: Read a => [String] -> Maybe a
-    argRead ss = getLast $ mconcat $ Last . readMaybe <$> ss
-
-    -- | Indicate this argument is mandatory
-    needArg :: Proxy a -> Bool
-    needArg _ = True
-```
-
-Suppose you are adding a support for your type `T`.
-We explain which function to define explicitly, depending on the
-property of `T`.
-
-If `T` is the type of the final value you take out of a command line,
-you do not have to define `Unwrap`. If `T` is a wrapper like `Def`,
-define `type Unwrap T = <unwrapped type>`. For `Def x y`,
-`type Unwrap (Def x y) = y`. If you defined `Unwrap`, define `unwrap`
-that takes an actual value out of the wrapped value.
-
-`argRead` is the main function that converts String into a value.
-If the type is an instance of `Read` and you are satisfied with
-how `read` converts a `String` into value, there is no need to
-define your own `argRead`. Otherwise, you define a function that
-converts a `String` into a value of the target type. When parsing
-is successful, return `Just`. When it fails, return `Nothing`.
-If the input is `[]`, it indicates the option does not have an
-argument; otherwise the input is a list of a single `String`.
-Last but not least, define `needArg _ = False` when the option
-allows us to omit the associated value; consider a boolean
-option like `--help`.
+# optparse-declarative++[![Hackage](https://matrix.hackage.haskell.org/api/v2/packages/optparse-declarative/badge)](http://hackage.haskell.org/package/optparse-declarative) [![GitHub Actions: test](https://github.com/tanakh/optparse-declarative/workflows/test/badge.svg)](https://github.com/tanakh/optparse-declarative/actions?query=workflow%3Atest) [![Join the chat at https://gitter.im/optparse-declarative/community](https://badges.gitter.im/optparse-declarative/community.svg)](https://gitter.im/optparse-declarative/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)++`optparse-declarative` is a declarative and easy-to-use command-line option parser.++# Install++```bash+$ cabal install optparse-declarative+```++# Usage++## Writing a simple command++First, you need to enable `DataKinds` extension. Then import `Options.Declarative` module.++```hs+{-# LANGUAGE DataKinds #-}+import           Options.Declarative+```++Next, define command line options as a **type of the function**.+For example, this is a simple greeting program with `-g` option that+takes a message of type `String` and an unnamed command-line argument+that specifies a name:++```hs+greet :: Flag "g" '["greet"] "STRING" "greeting message" (Def "Hello" String)+      -> Arg "NAME" String+      -> Cmd "Greeting command" ()+greet msg name =+    liftIO $ putStrLn $ get msg ++ ", " ++ get name ++ "!"+```++There are two types of options, `Flag` and `Arg`.+`Flag` represents a named argument (e.g., `--greet "Hola"`), and `Arg` an unnamed argument (e.g., `John` of `greet --greet Hola John`).+The last argument of `Flag` and `Arg` is the type of the value of the+argument; in this example, they are both `String`.+You can specify any type for the value as long as the type is an+instance of `ArgRead` typeclass, in which the conversion function+from `String` to the specified type is defined.+`Options.Declarative` provides following instances of `ArgRead`+typeclass.++- Int+- Integer+- Bool+- Double+- String+- (ArgRead a) => Maybe a++Users can add a new instance of `ArgRead` to support any user-defined type.+Please see Section "How to add a new instance of `ArgRead`" for details.++If you wish to specify a default value for allowing users to omit a+value, use the modifier `Def` with the default value as the second type argument (and the third type argument is the type of the value).+You need to specify the default value in `String` instead of the final+value of the target type; the string will be converted to the final+value via `ArgRead` typeclass.++In the example above, the variable `msg` has a very complex type (`Flag "g" '["greet"] "STRING" "greeting message" (Def "Hello" String)`).+In order to get the value of the target type (in this case, that is `String`),+you can use `get` function.++The whole type of command is `Cmd`.+`Cmd` is an instance of `MonadIO` and it has some extra information.++Finally, you can run the whole program by `run_`.++```hs+main :: IO ()+main = run_ greet+```++Here is an example session with the program shown above.++```bash+$ ghc simple.hs++$ ./simple+simple: not enough arguments+Try 'simple --help' for more information.++$ ./simple --help+Usage: simple [OPTION...] NAME+Options:+  -g STRING  --greet=STRING  greeting message+  -?         --help          display this help and exit++$ ./simple World+Hello, World!++$ ./simple --greet=Goodbye World+Goodbye, World!+```++Note that only the final option is used when multiple options of the+same name are given. This behavior emulates the behavior of a naive+program that uses GNU Getopt.++```bash+$ ./simple --greet=Hello --greet=Goodbye World+Goodbye, World!+```++There is another way of interpreting multiple options of the same name.+Suppose if you need to get multiple values from the same option.+Say, you wish to get `["Hello", "Goodbye"]` from the command-line+option `--greet=Hello --greeet=Goodbye`. Then, you can use+the type `[]` to indicate that it accepts multiple values.+The first line of the function `greet` in the example above+would be changed as this:++```hs+greet :: Flag "g" '["greet"] "STRING" "greeting message" [String]+```++The value returned by `get` will be a value of type `[String]`.+See the complete working example at `example/list.hs` for details.+++## Writing multiple subcommands++You can write (nested) subcommands.+You don't know what subcommands are? Imagine `git` command.+`git` has subcommands such as `git add`, `git commit`, `git log`, etc.+`git` has nested subcommands such as `git remote add`, `git remote rm`,+etc.+`optparse-declarative` provides an easy way to provide such possibly+nested subcommands.++Just group subcommands by `Group`, then you get a subcommand parser.+Here is an example with two subcommands `greet` and `connect`:++```hs+{-# LANGUAGE DataKinds #-}++import           Options.Declarative++main :: IO ()+main = run_ $+    Group "Test program for library"+    [ subCmd "greet"   greet+    , subCmd "connect" connect+    ]++greet :: Flag "g" '["greet"] "STRING" "greeting message" (Def "Hello" String)+      -> Flag "" '["decolate"] "" "decolate message" Bool+      -> Arg "NAME" String+      -> Cmd "Greeting command" ()+greet msg deco name = do+    let f x | get deco = "*** " ++ x ++ " ***"+            | otherwise = x+    liftIO $ putStrLn $ f $ get msg ++ ", " ++ get name ++ "!"++connect :: Flag "h" '["host"] "HOST" "host name"   (Def "localhost" String)+        -> Flag "p" '["port"] "PORT" "port number" (Def "8080"      Int   )+        -> Cmd "Connect command" ()+connect host port = do+    let addr = get host ++ ":" ++ show (get port)+    liftIO $ putStrLn $ "connect to " ++ addr+```++This is a sample session for the program above:++```bash+$ ./subcmd --help+Usage: subcmd [OPTION...] <COMMAND> [ARGS...]+Options:+  -?  --help  display this help and exit++Commands:+  greet       Greeting command+  port        Server command++$ ./subcmd connect --port=1234+connect to localhost:1234+```++If you wish to specify the program name or the version number,+use `run` instead of `run_`. The first argument of `run` is+a program name (of type `String`). The second argument is+a version number (of type `Maybe String`).++```hs+main :: IO ()+main = run "program_name" (Just "1.3.2") $+    Group "Test program for library"+    [ subCmd "greet"   greet+    , subCmd "connect" connect+    ]+```++For more examples, please see `example` directory.+++## Default options+`optparse-declarative` provides a few default options.+For example, `--help` is defined automatically so users do not have to+write it by their own. If run with `run` and the version number,+`--version` is defined automatically. Also, `--verbosity` option (`-v`+for short) is defined by default.+`getVerbosity` returns the verbosity level in `Int`.+`-v` gives 1, `-vv` gives 2, `-vvv` gives 3.+Alternatively, `--verbose=3` would yield 3.+++## How to add a new instance of `ArgRead`+Users need to create an instance of `ArgRead` for supporting a new type+for the command line argument. Here is the definition of class+`ArgRead`.++```hs+class ArgRead a where+    -- | Type of the argument+    type Unwrap a :: *+    type Unwrap a = a++    -- | Get the argument's value+    unwrap :: a -> Unwrap a+    default unwrap :: a ~ Unwrap a => a -> Unwrap a+    unwrap = id++    -- | Argument parser+    argRead :: [String] -> Maybe a+    default argRead :: Read a => [String] -> Maybe a+    argRead ss = getLast $ mconcat $ Last . readMaybe <$> ss++    -- | Indicate this argument is mandatory+    needArg :: Proxy a -> Bool+    needArg _ = True+```++Suppose you are adding a support for your type `T`.+We explain which function to define explicitly, depending on the+property of `T`.++If `T` is the type of the final value you take out of a command line,+you do not have to define `Unwrap`. If `T` is a wrapper like `Def`,+define `type Unwrap T = <unwrapped type>`. For `Def x y`,+`type Unwrap (Def x y) = y`. If you defined `Unwrap`, define `unwrap`+that takes an actual value out of the wrapped value.++`argRead` is the main function that converts String into a value.+If the type is an instance of `Read` and you are satisfied with+how `read` converts a `String` into value, there is no need to+define your own `argRead`. Otherwise, you define a function that+converts a `String` into a value of the target type. When parsing+is successful, return `Just`. When it fails, return `Nothing`.+If the input is `[]`, it indicates the option does not have an+argument; otherwise the input is a list of a single `String`.+Last but not least, define `needArg _ = False` when the option+allows us to omit the associated value; consider a boolean+option like `--help`.
example/bool.hs view
@@ -1,12 +1,12 @@-{-# LANGUAGE DataKinds #-}
-
-import           Control.Monad.Trans
-import           Options.Declarative
-
-main' :: Flag "b" '["bool"] "STRING" "boolean flag" Bool
-      -> Cmd "Simple greeting example" ()
-main' b =
-    liftIO $ putStrLn $ if get b then "Flag is True" else "Flag is False"
-
-main :: IO ()
-main = run_ main'
+{-# LANGUAGE DataKinds #-}++import           Control.Monad.Trans+import           Options.Declarative++main' :: Flag "b" '["bool"] "STRING" "boolean flag" Bool+      -> Cmd "Simple greeting example" ()+main' b =+    liftIO $ putStrLn $ if get b then "Flag is True" else "Flag is False"++main :: IO ()+main = run_ main'
example/list.hs view
@@ -1,18 +1,18 @@-{-# LANGUAGE DataKinds #-}
-
-import           Control.Monad
-import           Control.Monad.Trans
-import           Options.Declarative
-
-greet :: Flag "n" '["name"] "STRING" "name" [String]
-      -> Cmd "Count the number of people" ()
-greet name =
-    let people_name_list = get name
-        num_people = length people_name_list
-    in liftIO $ do
-        putStrLn $ "There are " ++ show num_people ++ " people on the list."
-        putStrLn " -- "
-        forM_ people_name_list putStrLn
-
-main :: IO ()
-main = run_ greet
+{-# LANGUAGE DataKinds #-}++import           Control.Monad+import           Control.Monad.Trans+import           Options.Declarative++greet :: Flag "n" '["name"] "STRING" "name" [String]+      -> Cmd "Count the number of people" ()+greet name =+    let people_name_list = get name+        num_people = length people_name_list+    in liftIO $ do+        putStrLn $ "There are " ++ show num_people ++ " people on the list."+        putStrLn " -- "+        forM_ people_name_list putStrLn++main :: IO ()+main = run_ greet
example/nonstrargs.hs view
@@ -1,13 +1,13 @@-{-# LANGUAGE DataKinds #-}
-
-import           Control.Monad.Trans
-import           Options.Declarative
-
-sum' :: Arg "N" Int
-     -> Arg "NS" [Int]
-     -> Cmd "Simple greeting example" ()
-sum' n ns =
-    liftIO $ putStrLn $ show (get n) ++ ", " ++ show (sum $ get ns)
-
-main :: IO ()
-main = run_ sum'
+{-# LANGUAGE DataKinds #-}++import           Control.Monad.Trans+import           Options.Declarative++sum' :: Arg "N" Int+     -> Arg "NS" [Int]+     -> Cmd "Simple greeting example" ()+sum' n ns =+    liftIO $ putStrLn $ show (get n) ++ ", " ++ show (sum $ get ns)++main :: IO ()+main = run_ sum'
optparse-declarative.cabal view
@@ -1,6 +1,6 @@ cabal-version:       2.2 name:                optparse-declarative-version:             0.4.2+version:             0.4.3 synopsis:            Declarative command line option parser description:         Declarative and easy to use command line option parser homepage:            https://github.com/tanakh/optparse-declarative@@ -11,6 +11,10 @@ copyright:           2020 Kazuki Okamoto (岡本和樹), (c) Hideyuki Tanaka 2015 category:            System build-type:          Simple+tested-with:         GHC == 9.2.8+                     GHC == 9.4.4+                     GHC == 9.6.2+   extra-source-files:  README.md                      ChangeLog.md
src/Options/Declarative.hs view
@@ -45,6 +45,7 @@ import           Control.Applicative import           Control.Monad import           Control.Monad.Catch+import           Control.Monad.Fix import           Control.Monad.Reader import           Data.List import           Data.Maybe