on master help sign in
Remove wai-handler-devel
commit2a41f7a068ab24b15d5758a00a1799c1e729e911 authorMichael Snoyman <michael@snoyman.com> dateWed 26 Mar 2014, 14:07 (13 years ago) parentbe19359
17 files changed−569
wai-handler-devel/.ghci−1 wai-handler-devel/.gitignore−2 wai-handler-devel/FullApp.hs−47 wai-handler-devel/LICENSE−20 wai-handler-devel/Network/Wai/Application/Devel.hs−59 wai-handler-devel/Network/Wai/Handler/DevelServer.hs−215 wai-handler-devel/Network/Wai/Handler/DevelServer/Compat.hs−19 wai-handler-devel/README wai-handler-devel/Setup.lhs−11 wai-handler-devel/SmallApp.hs−12 wai-handler-devel/hamlet/testapp.hamlet−9 wai-handler-devel/run-fullapp.hs−4 wai-handler-devel/run-onreloadapp.hs−23 wai-handler-devel/run-smallapp.hs−6 wai-handler-devel/wai-handler-devel-unwatched.hs−27 wai-handler-devel/wai-handler-devel.cabal−51 wai-handler-devel/wai-handler-devel.hs−63
wai-handler-devel/.ghcideleted−1
@@ -1 +0,0 @@
1−:set -optP-include -optPdist/build/autogen/cabal_macros.h
wai-handler-devel/.gitignoredeleted−2
@@ -1,2 +0,0 @@
1−*.swp
2−/dist/
wai-handler-devel/FullApp.hsdeleted−47
@@ -1,47 +0,0 @@
1−{-# LANGUAGE QuasiQuotes, TypeFamilies, GeneralizedNewtypeDeriving, GADTs #-}
2−{-# LANGUAGE TemplateHaskell #-}
3−{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE FlexibleContexts #-}
5−module FullApp (fullApp) where
6−
7−import Network.Wai
8−import Network.HTTP.Types
9−import Data.ByteString.Lazy.Char8 (pack)
10−import Database.Persist.TH
11−import Database.Persist.Sqlite
12−import System.Directory
13−import Control.Monad (when)
14−import Text.Hamlet
15−import Text.Blaze.Html.Renderer.Utf8 (renderHtml)
16−import Data.Text.Lazy.Encoding (encodeUtf16LE)
17−import Control.Monad.Trans.Resource (runResourceT)
18−import Control.Monad.IO.Class (liftIO)
19−
20−share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persist|
21−Dummy
22− dummy String
23−|]
24−
25−fullApp :: (Application -> IO ()) -> IO ()
26−fullApp handler = do
27− putStrLn "testApp called, this should happen only once per reload"
28− -- Swap between the following two lines as necessary to generate errors
29− exi <- doesFileExist "db"
30− --let exi = True
31− when exi $ removeFile "db"
32− withSqlitePool "db" 10 $ \pool -> do
33− flip runSqlPool pool $ runMigration migrateAll
34− handler $ \req -> do
35− if pathInfo req == ["favicon.ico"]
36− then return $ responseLBS status301 [("Location", "http://www.yesodweb.com/favicon.ico")]
37− $ pack ""
38− else do
39− liftIO $ print (pathInfo req)
40− x <- runResourceT $ flip runSqlPool pool $ do
41− _ <- insert (Dummy "")
42− count ([] :: [Filter Dummy])
43− return $ responseLBS status200
44− [("Content-Type", "text/html; charset=utf-8")] $
45− renderHtml
46− $(shamletFile "hamlet/testapp.hamlet")
47− putStrLn "handler completed, this should only happen at the beginning of a reload"
wai-handler-devel/LICENSEdeleted−20
@@ -1,20 +0,0 @@
1−Copyright (c) 2012 Michael Snoyman, http://www.yesodweb.com/
2−
3−Permission is hereby granted, free of charge, to any person obtaining
4−a copy of this software and associated documentation files (the
5−"Software"), to deal in the Software without restriction, including
6−without limitation the rights to use, copy, modify, merge, publish,
7−distribute, sublicense, and/or sell copies of the Software, and to
8−permit persons to whom the Software is furnished to do so, subject to
9−the following conditions:
10−
11−The above copyright notice and this permission notice shall be
12−included in all copies or substantial portions of the Software.
13−
14−THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15−EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16−MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17−NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18−LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19−OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20−WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
wai-handler-devel/Network/Wai/Application/Devel.hsdeleted−59
@@ -1,59 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−module Network.Wai.Application.Devel
3− ( -- * Types
4− AppHolder
5− , AppRunner
6− , WithAppRunner
7− -- * Functions
8− , initAppHolder
9− , swapApp
10− , swapAppSimple
11− , toApp
12− ) where
13−
14−import Control.Concurrent (forkIO)
15−import Control.Concurrent.MVar
16− ( MVar, newEmptyMVar, newMVar
17− , takeMVar, putMVar, readMVar
18− )
19−import Network.Wai (Application, responseLBS)
20−import Network.HTTP.Types (status500)
21−import Data.ByteString.Lazy.Char8 ()
22−import Control.Monad.IO.Class (liftIO)
23−
24−type AppHolder = MVar (Application, MVar ())
25−type AppRunner = Application -> IO ()
26−type WithAppRunner = AppRunner -> IO ()
27−
28−initAppHolder :: IO AppHolder
29−initAppHolder = do
30− flag <- newEmptyMVar
31− newMVar (initApp, flag)
32− where
33− initApp _ = return
34− $ responseLBS status500 [("Content-Type", "text/plain")]
35− $ "No app has yet been loaded"
36−
37−swapAppSimple :: Application -> AppHolder -> IO ()
38−swapAppSimple app =
39− swapApp war
40− where
41− war f = f app
42−
43−swapApp :: WithAppRunner -> AppHolder -> IO ()
44−swapApp war ah = void $ forkIO $ war $ \app -> do
45− (_, oldFlag) <- takeMVar ah
46− -- allow the old app to cleanup
47− putMVar oldFlag ()
48− -- now place the new app into the AppHolder, waiting for a termination
49− -- signal
50− flag <- newEmptyMVar
51− putMVar ah (app, flag)
52− takeMVar flag -- this causes execution to hang until we are terminated
53− where
54− void x = x >> return ()
55−
56−toApp :: AppHolder -> Application
57−toApp ah req = do
58− (app, _) <- liftIO $ readMVar ah
59− app req
wai-handler-devel/Network/Wai/Handler/DevelServer.hsdeleted−215
@@ -1,215 +0,0 @@
1−{-# LANGUAGE DeriveDataTypeable #-}
2−{-# LANGUAGE FlexibleContexts #-}
3−{-# LANGUAGE OverloadedStrings #-}
4−{-# LANGUAGE FlexibleInstances #-}
5−module Network.Wai.Handler.DevelServer
6− ( run
7− , runQuit
8− , runNoWatch
9− , runWithReloadActions
10− , runQuitWithReloadActions
11− ) where
12−
13−import Language.Haskell.Interpreter hiding (typeOf)
14−import Network.Wai
15−import Network.HTTP.Types (status200)
16−
17−import Data.Text.Lazy (pack)
18−import Data.Text.Lazy.Encoding (encodeUtf8)
19−import qualified Data.ByteString.Lazy.Char8 as L8
20−import Control.Exception (Exception, SomeException, toException, fromException, finally, mask)
21−import qualified Control.Exception as E
22−import Control.Concurrent (ThreadId, myThreadId, threadDelay, killThread)
23−import qualified Control.Concurrent as Concurrent
24−
25−import Data.Maybe
26−import Control.Monad
27−import Control.Concurrent.MVar
28−
29−import qualified Network.Wai.Handler.Warp as Warp
30−import Network.Wai.Application.Devel
31−import Network.Wai.Middleware.RequestLogger (logStdoutDev)
32−
33−import Data.List (nub, group, sort)
34−
35−import Network.Wai.Handler.DevelServer.Compat
36−
37−type FunctionName = String
38−
39−runNoWatch :: Int -> ModuleName -> FunctionName
40− -> (FilePath -> IO [FilePath]) -> IO ()
41−runNoWatch port modu func extras = do
42− ah <- initAppHolder
43− _ <- reload modu func extras Nothing ah []
44− Warp.run port $ toApp ah
45−
46−runQuit :: Int -> ModuleName -> FunctionName -> (FilePath -> IO [FilePath])
47− -> IO ()
48−runQuit port modu func extras = runQuitWithReloadActions port modu func extras []
49−
50−-- |
51−-- A version of `Concurrent.forkIO` that re-throws any uncaught
52−-- `E.UserInterrupt` from the child thread in the parent thread.
53−--
54−-- We need this because using hint (or the GHC API) causes @UserInterrupt@ to
55−-- occur in the thread that runs `runInterpreter` instead of the main thread.
56−forkIO :: IO () -> IO ThreadId
57−forkIO action = do
58− threadId <- myThreadId
59− Concurrent.forkIO (action `E.catch` \e -> case e of
60− E.UserInterrupt -> E.throwTo threadId e
61− _ -> E.throwIO e
62− )
63−
64−runQuitWithReloadActions :: Int -> ModuleName -> FunctionName -> (FilePath -> IO [FilePath])
65− -> [IO (IO ())] -> IO ()
66−runQuitWithReloadActions port modu func extras actions = do
67− sig <- newEmptyMVar
68− mask $ \unmask -> do
69− threadId <- forkIO $ runWithReloadActions port modu func extras (Just sig) actions
70− unmask (go sig) `finally` killThread threadId
71− where
72− go sig = do
73− x <- getLine
74− case x of
75− 'q':_ -> putStrLn "Quitting, goodbye!"
76− 'r':_ -> do
77− putStrLn "Forcing reinterpretation"
78− _ <- tryPutMVar sig ()
79− go sig
80− _ -> go sig
81−
82−runWithReloadActions :: Int -> ModuleName -> FunctionName -> (FilePath -> IO [FilePath])
83− -> Maybe (MVar ()) -> [IO (IO ())] -> IO ()
84−runWithReloadActions port modu func extras msig initActions = do
85− actions <- mapM id initActions
86− ah <- initAppHolder
87− mask $ \unmask -> do
88− threadId <- forkIO $ fillApp modu func extras ah msig actions
89− unmask (Warp.run port $ toApp ah) `finally` killThread threadId
90−
91−run :: Int -> ModuleName -> FunctionName -> (FilePath -> IO [FilePath]) -> Maybe (MVar ())
92− -> IO ()
93−run port modu func extras msig = runWithReloadActions port modu func extras msig []
94−
95−{-
96−startApp :: Queue -> Handler -> IO ()
97−startApp queue withApp = do
98− forkIO (withApp go) >> return ()
99− where
100− go app = do
101− msession <- C.readChan queue
102− case msession of
103− Nothing -> return ()
104− Just (req, onRes) -> do
105− void $ forkIO $ (E.handle onErr $ app req) >>= onRes
106− go app
107− onErr :: SomeException -> IO Response
108− onErr e = return
109− $ responseLBS
110− status500
111− [("Content-Type", "text/plain; charset=utf-8")]
112− $ charsToLBS
113− $ "Exception thrown while running application\n\n" ++ show e
114− void x = x >> return ()
115−-}
116−
117−getTimes :: [FilePath] -> IO [TimeStamp]
118−getTimes = E.handle (constSE $ return []) . mapM getTimeStamp
119−
120−constSE :: x -> SomeException -> x
121−constSE = const
122−
123−fillApp :: String -> String
124− -> (FilePath -> IO [FilePath]) -> AppHolder -> Maybe (MVar ()) -> [IO ()] -> IO ()
125−fillApp modu func dirs ah msig actions =
126− go Nothing []
127− where
128− go prevError prevFiles = do
129− forceReload <- maybe (return False) (fmap isJust . tryTakeMVar) msig
130− toReload <-
131− if forceReload || null prevFiles
132− then return True
133− else do
134− times <- getTimes $ map fst prevFiles
135− return $ times /= map snd prevFiles
136− (newError, newFiles) <-
137− if toReload
138− then reload modu func dirs prevError ah actions
139− else return (prevError, prevFiles)
140− threadDelay 1000000
141− go newError newFiles
142−
143−reload :: String -> String
144− -> (FilePath -> IO [FilePath])
145− -> Maybe SomeException
146− -> AppHolder
147− -> [IO ()]
148− -> IO (Maybe SomeException, [(FilePath, TimeStamp)])
149−reload modu func extras prevError ah actions = do
150− case prevError of
151− Nothing -> putStrLn "Attempting to interpret your app..."
152− _ -> return ()
153− loadingApp' prevError ah
154− res <- theapp modu func
155− case res of
156− Left err -> do
157− when (show (Just err) /= show prevError) $
158− putStrLn $ "Compile failed: " ++ showInterpError err
159− loadingApp' (Just $ toException err) ah
160− return (Just $ toException err, [])
161− Right (app, files') -> E.handle onInitErr $ do
162− files'' <- mapM extras files'
163− let files = map head $ group $ sort $ concat $ files' : files''
164− putStrLn "Interpreting success, new app loaded"
165− E.handle onInitErr $ do
166− swapApp (\f -> app $ f . logStdoutDev) ah
167− times <- getTimes files
168− sequence_ actions
169− return (Nothing, zip files times)
170− where
171− onInitErr e = do
172− putStrLn $ "Error initializing application: " ++ show e
173− loadingApp' (Just e) ah
174− return (Just e, [])
175−
176−showInterpError :: InterpreterError -> String
177−showInterpError (WontCompile errs) =
178− concat . nub $ map (\(GhcError msg) -> '\n':'\n':msg) errs
179−showInterpError err = show err
180−
181−loadingApp' :: Maybe SomeException -> AppHolder -> IO ()
182−loadingApp' err = swapApp (loadingApp err)
183−
184−loadingApp :: Maybe SomeException -> Handler
185−loadingApp err f =
186− f $ const $ return $ responseLBS status200
187− ( ("Content-Type", "text/plain")
188− : case err of
189− Nothing -> [("Refresh", "1")]
190− Just _ -> []
191− ) $ toMessage err
192− where
193− toMessage Nothing = "Loading code changes, please wait"
194− toMessage (Just err') = charsToLBS $ "Error loading code: " ++
195− (case fromException err' of
196− Just e -> showInterpError e
197− Nothing -> show err')
198−
199−charsToLBS :: String -> L8.ByteString
200−charsToLBS = encodeUtf8 . pack
201−
202−type Handler = (Application -> IO ()) -> IO ()
203−
204−theapp :: String -> String -> IO (Either InterpreterError (Handler, [FilePath]))
205−theapp modu func =
206− runInterpreter $ do
207− loadModules [modu]
208− mods <- getLoadedModules
209− setImports ["Prelude", "Network.Wai", "Data.ByteString.Internal", "Control.Monad.Trans.Resource", modu]
210− app <- interpret func infer
211− return (app, map toFile mods)
212− where
213− toFile s = map toSlash s ++ ".hs"
214− toSlash '.' = '/'
215− toSlash c = c
wai-handler-devel/Network/Wai/Handler/DevelServer/Compat.hsdeleted−19
@@ -1,19 +0,0 @@
1−{-# LANGUAGE CPP #-}
2−module Network.Wai.Handler.DevelServer.Compat (
3− TimeStamp
4−, getTimeStamp
5−) where
6−
7−import System.Directory (getModificationTime)
8−
9−#if MIN_VERSION_directory(1,2,0)
10−import Data.Time.Clock (UTCTime)
11−newtype TimeStamp = TimeStamp UTCTime
12−#else
13−import System.Time (ClockTime)
14−newtype TimeStamp = TimeStamp ClockTime
15−#endif
16− deriving Eq
17−
18−getTimeStamp :: FilePath -> IO TimeStamp
19−getTimeStamp = fmap TimeStamp . getModificationTime
wai-handler-devel/READMEdeleted

No changes to the content.

wai-handler-devel/Setup.lhsdeleted−11
@@ -1,11 +0,0 @@
1−#!/usr/bin/env runhaskell
2−
3−> module Main where
4−> import Distribution.Simple
5−> import System.Cmd (system)
6−
7−> main :: IO ()
8−> main = defaultMainWithHooks (simpleUserHooks { runTests = runTests' })
9−
10−> runTests' :: a -> b -> c -> d -> IO ()
11−> runTests' _ _ _ _ = system "runhaskell -DTEST runtests.hs" >> return ()
wai-handler-devel/SmallApp.hsdeleted−12
@@ -1,12 +0,0 @@
1−{-# LANGUAGE OverloadedStrings #-}
2−module SmallApp where
3−
4−import Network.Wai
5−import Network.HTTP.Types
6−import Data.ByteString.Lazy.Char8 ()
7−
8−testapp' :: Application
9−testapp' _ = return $ responseLBS status200 [("Content-Type", "text/html")] "test"
10−
11−smallApp :: (Application -> IO ()) -> IO ()
12−smallApp f = f testapp'
wai-handler-devel/hamlet/testapp.hamletdeleted−9
@@ -1,9 +0,0 @@
1−$doctype 5
2−<html>
3− <head>
4− <meta charset=utf-8>
5− <title>Full App
6− <body>
7− <h1>Hello World
8− <p>Counter: #{show x}
9− <p>שלום
wai-handler-devel/run-fullapp.hsdeleted−4
@@ -1,4 +0,0 @@
1−import Network.Wai.Handler.DevelServer (runQuit)
2−
3−main :: IO ()
4−main = runQuit 3000 "FullApp" "fullApp" (const $ return ["hamlet/testapp.hamlet"])
wai-handler-devel/run-onreloadapp.hsdeleted−23
@@ -1,23 +0,0 @@
1−
2−import Network.Wai.Handler.DevelServer (runQuitWithReloadActions)
3−import System.Directory(findExecutable)
4−import System.Process(readProcess)
5−
6−main :: IO ()
7−main = runQuitWithReloadActions 4000 "SmallApp" "smallApp" (const $ return []) [browserRefresh]
8−
9−browserRefresh :: IO (IO ())
10−browserRefresh = do
11− exe <- findExecutable "xdotool"
12− case exe of
13− Nothing -> do
14− putStrLn "Install xdotool for automatic browser refresh"
15− return $ return ()
16− Just xdotool -> do
17− putStrLn "Please click on the browser window..."
18− pid <- readProcess xdotool ["selectwindow"] ""
19− return $ do
20− current <- readProcess xdotool ["getwindowfocus"] ""
21− let cmds = ["windowfocus", pid, "key", "F5", "windowfocus", current]
22− _ <- readProcess xdotool cmds ""
23− return ()
wai-handler-devel/run-smallapp.hsdeleted−6
@@ -1,6 +0,0 @@
1−import Network.Wai.Handler.DevelServer (runQuit)
2−
3−main :: IO ()
4−main = do
5− putStrLn "http://localhost:3000"
6− runQuit 3000 "SmallApp" "smallApp" (const $ return [])
wai-handler-devel/wai-handler-devel-unwatched.hsdeleted−27
@@ -1,27 +0,0 @@
1−{-# LANGUAGE DeriveDataTypeable #-}
2−import Network.Wai.Handler.DevelServer (runNoWatch)
3−import System.Console.CmdArgs
4−import Control.Concurrent (forkIO)
5−
6−data Devel = Devel
7− { port :: Int
8− , moduleName :: String
9− , function :: String
10− }
11− deriving (Show, Data, Typeable)
12−
13−main :: IO ()
14−main = do
15− Devel p m f <- cmdArgs $ Devel
16− { port = 3000 &= argPos 0 &= typ "PORT"
17− , moduleName = "" &= argPos 1 &= typ "MODULE"
18− , function = "" &= argPos 2 &= typ "FUNCTION"
19− } &= summary "WAI development web server"
20− _ <- forkIO $ runNoWatch p m f $ const $ return []
21− go
22− where
23− go = do
24− x <- getLine
25− case x of
26− 'q':_ -> putStrLn "Quitting, goodbye!"
27− _ -> go
wai-handler-devel/wai-handler-devel.cabaldeleted−51
@@ -1,51 +0,0 @@
1−Name: wai-handler-devel
2−Version: 2.0.0.2
3−Synopsis: WAI server that automatically reloads code after modification. (deprecated)
4−Description: This handler automatically reloads your source code upon any changes. It works by using the hint package, essentially embedding GHC inside the handler. The handler (both the executable and library) takes three arguments: the port to listen on, the module name containing the application function, and the name of the function.
5− .
6− One major note: the type of the application is most likely not what you expect. A common case for WAI applications is having a withApplication function, and this library assumes this is the case. Therefore, the type signature of your application function must be:
7− .
8− > withYourApp :: (Application -> IO ()) -> IO ()
9−License: MIT
10−License-file: LICENSE
11−Author: Michael Snoyman
12−Maintainer: michael@snoyman.com
13−Homepage: http://github.com/yesodweb/wai
14−Category: Web
15−Build-Type: Simple
16−Cabal-Version: >=1.6
17−Stability: Stable
18−
19−Source-repository head
20− type: git
21− location: git://github.com/yesodweb/wai.git
22−
23−Library
24− Build-Depends: base >= 4 && < 5
25− , wai >= 2.0 && < 2.2
26− , wai-extra >= 2.0 && < 2.2
27− , http-types >= 0.7
28− , warp >= 2.0 && < 2.2
29− , directory >= 1.0.1
30− , network >= 2.2.1.5
31− , bytestring >= 0.9.1.4
32− , hint >= 0.3.2.3 && < 0.5
33− , text >= 0.7
34− , old-time
35− , time
36− , transformers >= 0.2.2
37− , attoparsec >= 0.10
38− Exposed-modules: Network.Wai.Handler.DevelServer
39− Network.Wai.Application.Devel
40− Other-modules: Network.Wai.Handler.DevelServer.Compat
41− ghc-options: -Wall
42−
43−Executable wai-handler-devel
44− Build-Depends: cmdargs >= 0.4
45− ghc-options: -Wall -threaded
46− main-is: wai-handler-devel.hs
47−
48−Executable wai-handler-devel-unwatched
49− Build-Depends: cmdargs >= 0.4
50− ghc-options: -Wall -threaded
51− main-is: wai-handler-devel-unwatched.hs
wai-handler-devel/wai-handler-devel.hsdeleted−63
@@ -1,63 +0,0 @@
1−{-# LANGUAGE DeriveDataTypeable #-}
2−{-# LANGUAGE OverloadedStrings #-}
3−import Network.Wai.Handler.DevelServer (runQuit)
4−import System.Console.CmdArgs
5−import qualified Data.Attoparsec.Text.Lazy as A
6−import qualified Data.Text.Lazy.IO as TIO
7−import Control.Applicative ((<|>), many)
8−import Data.Char (isSpace)
9−import Data.Maybe (mapMaybe)
10−
11−data Devel = Devel
12− { port :: Int
13− , moduleName :: String
14− , function :: String
15− , yesod :: Bool
16− }
17− deriving (Show, Data, Typeable)
18−
19−main :: IO ()
20−main = do
21− Devel p m f y <- cmdArgs $ Devel
22− { port = 3000 &= argPos 0 &= typ "PORT"
23− , moduleName = "" &= argPos 1 &= typ "MODULE"
24− , function = "" &= argPos 2 &= typ "FUNCTION"
25− , yesod = False
26− } &= summary "WAI development web server"
27− runQuit p m f $ if y then determineHamletDeps else (const $ return [])
28−
29−data TempType = Hamlet | Cassius | Lucius | Julius | Widget | Verbatim
30− deriving Show
31−
32−determineHamletDeps :: FilePath -> IO [FilePath]
33−determineHamletDeps x = do
34− y <- TIO.readFile x
35− let z = A.parse (many $ (parser <|> (A.anyChar >> return Nothing))) y
36− case z of
37− A.Fail{} -> return []
38− A.Done _ r -> return $ mapMaybe go r
39− where
40− go (Just (Hamlet, f)) = Just $ "hamlet/" ++ f ++ ".hamlet"
41− go (Just (Widget, f)) = Just $ "hamlet/" ++ f ++ ".hamlet"
42− go (Just (Verbatim, f)) = Just f
43− go _ = Nothing
44− parser = do
45− ty <- (A.string "$(hamletFile " >> return Hamlet)
46− <|> (A.string "$(cassiusFile " >> return Cassius)
47− <|> (A.string "$(luciusFile " >> return Lucius)
48− <|> (A.string "$(juliusFile " >> return Julius)
49− <|> (A.string "$(widgetFile " >> return Widget)
50− <|> (A.string "$(Settings.hamletFile " >> return Hamlet)
51− <|> (A.string "$(Settings.cassiusFile " >> return Cassius)
52− <|> (A.string "$(Settings.luciusFile " >> return Lucius)
53− <|> (A.string "$(Settings.juliusFile " >> return Julius)
54− <|> (A.string "$(Settings.widgetFile " >> return Widget)
55− <|> (A.string "$(persistFile " >> return Verbatim)
56− <|> (A.string "$(parseRoutesFile " >> return Verbatim)
57− A.skipWhile isSpace
58− _ <- A.char '"'
59− y <- A.many1 $ A.satisfy (/= '"')
60− _ <- A.char '"'
61− A.skipWhile isSpace
62− _ <- A.char ')'
63− return $ Just (ty, y)