Skip to content

Commit 4764708

Browse files
committed
Parse options with optparse-applicative
Also ddd shelltestrunner tests.
1 parent f11ceaa commit 4764708

File tree

7 files changed

+144
-44
lines changed

7 files changed

+144
-44
lines changed

exe/Main.hs

Lines changed: 12 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
-- (C) vasylp https://github.com/vasylp/hgettext/blob/master/src/hgettext.hs
22

3-
import qualified Language.Haskell.Exts as H
3+
import qualified Language.Haskell.Exts as H
4+
5+
import Options
46

57
import System.Environment
68
import System.Console.GetOpt
@@ -21,39 +23,8 @@ import Data.Version (showVersion)
2123
version = undefined
2224
-- import Paths_haskell_gettext (version)
2325

24-
data Options = Options {
25-
outputFile :: String,
26-
keywords :: [String],
27-
printVersion :: Bool
28-
} deriving Show
29-
30-
options :: [OptDescr (Options->Options)]
31-
options =
32-
[
33-
Option ['o'] ["output"]
34-
(ReqArg (\o opts -> opts {outputFile = o}) "FILE")
35-
"write output to specified file",
36-
Option ['d'] ["default-domain"]
37-
(ReqArg (\d opts -> opts {outputFile = d ++ ".po"}) "NAME")
38-
"use NAME.po instead of messages.po",
39-
Option ['k'] ["keyword"]
40-
(ReqArg (\d opts -> opts {keywords = d: keywords opts}) "WORD")
41-
"function names, in which searched words are wrapped. Can be used multiple times, for multiple funcitons",
42-
Option [] ["version"]
43-
(NoArg (\opts -> opts {printVersion = True}))
44-
"print version of hgettexts"
45-
]
46-
47-
48-
defaultOptions = Options "messages.po" ["__", "lprintf"] False
49-
50-
parseArgs :: [String] -> IO (Options, [String])
51-
parseArgs args =
52-
case getOpt Permute options args of
53-
(o, n, []) -> return (foldl (flip id) defaultOptions o, n)
54-
(_, _, errs) -> ioError (userError (concat errs ++ usageInfo header options))
55-
where header = "Usage: hgettext [OPTION] [INPUTFILE] ..."
56-
26+
-- xxx add default options
27+
-- defaultOptions = Options "messages.po" ["__", "lprintf"] False
5728

5829
toTranslate :: [String] -> H.ParseResult (H.Module H.SrcSpanInfo) -> [(H.SrcSpanInfo, String)]
5930
toTranslate f (H.ParseOk z) = nub [ (loc, s) | H.App _ (H.Var _ (H.UnQual _ (H.Ident _ x))) (H.Lit _ (H.String loc s _)) <- universeBi z, x `elem` f]
@@ -95,18 +66,16 @@ formatPotFile lines = do
9566
"\"Content-Transfer-Encoding: 8bit\\n\"",
9667
""]
9768

98-
process :: Options -> [String] -> IO ()
99-
process Options{printVersion = True} _ =
69+
process :: Options -> IO ()
70+
process Options{printVersion = True} =
10071
putStrLn $ "hgettext, version " ++ (showVersion version)
101-
102-
process opts fl = do
103-
t <- mapM read' fl
72+
process opts = do
73+
t <- mapM read' (inputFiles opts)
10474
pot <- formatPotFile $ map (\(n,c) -> formatMessages n $ toTranslate (keywords opts) c) t
10575
writeFile (outputFile opts) pot
10676
where read' "-" = getContents >>= \c -> return ("-", H.parseFileContents c)
10777
read' f = H.parseFile f >>= \m -> return (f, m)
10878

109-
main =
110-
getArgs >>= parseArgs >>= uncurry process
111-
112-
79+
main = do
80+
opts <- parseOptions
81+
process opts

exe/Options.hs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
module Options (
2+
Options(..),
3+
parseOptions
4+
)
5+
where
6+
7+
import Options.Applicative
8+
9+
import qualified System.FilePath as FP
10+
11+
data Options = Options {
12+
inputFiles :: [FilePath],
13+
outputFile :: FilePath,
14+
keywords :: [String],
15+
printVersion :: Bool
16+
} deriving Show
17+
18+
parseOptions :: IO Options
19+
parseOptions = execParser infoOpts
20+
21+
-------------------------------------------------------------------------------
22+
-- Parsers/properties
23+
24+
-- xxx test help
25+
infoOpts :: ParserInfo Options
26+
infoOpts = info (options <**> helper)
27+
( fullDesc
28+
<> progDesc "Extract translatable strings from Haskell source files."
29+
<> header "hello - a test for optparse-applicative" )
30+
31+
options :: Parser Options
32+
options = Options <$> inputs <*> outfile <*> many keyword <*> version
33+
34+
inputs :: Parser [FilePath]
35+
inputs = many (argument str (metavar "PATH..."))
36+
37+
outfile :: Parser FilePath
38+
outfile = output <|> ((FP.<.> "po") <$> defaultDomain) <|> pure "messages.po"
39+
where
40+
output :: Parser FilePath
41+
output = strOption
42+
( long "output"
43+
<> short 'o'
44+
<> metavar "FILE"
45+
<> help "Write output to specified file." )
46+
47+
defaultDomain :: Parser FilePath
48+
defaultDomain = strOption
49+
( long "default-domain"
50+
<> short 'd'
51+
<> metavar "NAME"
52+
<> help "Use NAME.po instead of messages.po." )
53+
54+
keyword :: Parser String
55+
keyword = strOption
56+
( long "keyword"
57+
<> short 'k'
58+
<> metavar "WORD"
59+
<> help "function names, in which searched words are \
60+
\wrapped. Can be used multiple times, for multiple \
61+
\funcitons." )
62+
63+
version :: Parser Bool
64+
version = switch
65+
( long "version"
66+
<> short 'v'
67+
<> help "Print version of hgettext" )

haskell-gettext.cabal

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,11 @@ library
6262
executable hgettext
6363
import: shared
6464
main-is: Main.hs
65+
other-modules: Options
6566
build-depends: filepath >= 1.4 && < 1.6,
6667
haskell-src-exts >= 1.18 && < 1.24,
67-
old-locale >= 1.0 && < 1.1
68+
old-locale >= 1.0 && < 1.1,
69+
optparse-applicative >= 0.18.1 && < 0.19,
6870
time >= 1.5.0 && < 1.13,
6971
uniplate >= 1.6.12 && < 1.7,
7072
hs-source-dirs: exe/

run-tests.sh

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
#! /bin/bash
2+
set -e
3+
4+
## TODO clean artifacts regardless
5+
6+
### Helpers
7+
8+
# Clean stale artifacts from previous runs.
9+
function cleanArtifacts {
10+
echo "Cleaning artifacts…"
11+
find test/shelltest/ -type f \
12+
-regextype posix-egrep -regex ".*\.po" -delete
13+
}
14+
15+
16+
### Program
17+
18+
clear
19+
20+
if ! which shelltest > /dev/null; then
21+
echo "shelltest not installed, install it (shelltestrunner)!"
22+
exit 1
23+
fi
24+
25+
cabal build hgettext
26+
Bin=$(cabal list-bin hgettext)
27+
28+
29+
# Run all tests, and clean before (always) and after (only if shelltest
30+
# exits without errors).
31+
cleanArtifacts
32+
shelltest --color --execdir --with "$Bin" test/shelltest/
33+
cleanArtifacts

test/shelltest/exceptions/empty.test

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# 1.Print helpful text on missing input.
2+
$ hgettext
3+
hgettext: missing arguments
4+
>= 0
5+
6+
# 2.Do not create messages.po on missing input.
7+
$ hgettext && ls
8+
> /!messages.po/
9+
>= 0

test/shelltest/options/Menu.hs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module Menu where
2+
3+
intro :: Loc a
4+
intro = __ "Welcome!"

test/shelltest/options/options.test

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# Get `output` argument.
2+
# 1. Get `output` argument.
3+
$ hgettext --output out.po && ls
4+
> /out.po/
5+
6+
# 2. Get `output` argument (short).
7+
$ hgettext -o out.po && ls
8+
> /out.po/
9+
10+
# 3. Get `default domain` argument.
11+
$ hgettext --default-domain dom && ls
12+
> /dom.po/
13+
14+
# 3. Get `default domain` argument (short).
15+
$ hgettext -d dom && ls
16+
> /dom.po/

0 commit comments

Comments
 (0)