bird 0.0.14 → 0.0.15
raw patch · 9 files changed
+84/−17 lines, 9 filesdep +MissingHPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: MissingH
API changes (from Hackage documentation)
+ Bird.Config: BirdConfig :: String -> (Request -> Router -> IO Reply) -> BirdConfig
+ Bird.Config: birdLogger :: BirdConfig -> Request -> Router -> IO Reply
+ Bird.Config: data BirdConfig
+ Bird.Config: instance Default BirdConfig
+ Bird.Config: staticDir :: BirdConfig -> String
+ Bird.Config: type Router = Request -> BirdResponder ()
+ Bird.Request: rawRequestUri :: Request -> String
- Bird.BirdResponder: type BirdResponder = StateT Reply (ReaderT Request IO)
+ Bird.BirdResponder: type BirdResponder = StateT Reply (ReaderT Request (WriterT [String] IO))
- Bird.Request: Request :: RequestMethod -> Path -> [(String, Maybe String)] -> Request
+ Bird.Request: Request :: RequestMethod -> Path -> [(String, Maybe String)] -> String -> Request
Files
- bin/bird.hs +15/−6
- bird.cabal +3/−3
- readme.markdown +5/−1
- src/Bird.hs +4/−0
- src/Bird/BirdResponder.hs +6/−2
- src/Bird/Config.hs +22/−0
- src/Bird/Logger.hs +17/−0
- src/Bird/Request.hs +5/−4
- src/Bird/Translator/Hack.hs +7/−1
bin/bird.hs view
@@ -20,12 +20,12 @@ system "ghc --make -O2 Main.hs" files <- getDirectoryContents appModuleNamePath system $ "rm *.o *.hi " ++ appModuleName ++ ".hs"- renameFile "Main" appModuleName+ renameFile "Main" (appModuleName ++ "App") return () ["fly"] -> do appModuleNamePath <- getCurrentDirectory appModuleName <- return $ head . reverse $ split '/' appModuleNamePath- system $ "./" ++ appModuleName+ system $ "./" ++ appModuleName ++ "App" return () ["hatch", appName] -> createBirdApp appName (action:_) -> do@@ -43,7 +43,8 @@ appModulePrelude appModuleName = "--This file is generated by bird. It will be overwritten the next time you run 'bird nest'. Edit at your own peril.\n" ++ "module " ++ appModuleName ++ " where\n" ++- "import Bird\n\n"+ "import Bird\n" +++ "import Prelude hiding( log )\n\n" appModuleEpilogue = "get _ = status 404\n" ++@@ -51,15 +52,22 @@ "put _ = status 404\n" ++ "delete _ = status 404\n" - createBirdApp a = do createDirectory a+ createDirectory (a ++ "/" ++ a ++ "/") writeFile (a ++ "/" ++ a ++ ".bird.hs") (routeFile a) writeFile (a ++ "/" ++ "Main.hs") (mainFile a)+ writeFile (a ++ "/" ++ a ++ "/Config.hs") (configFile a) putStrLn $ "A fresh Bird app has been created in " ++ a ++ "." routeFile a = "get [] = body \"Hello, Bird!\"" +configFile a = + "module " ++ a ++ ".Config where\n\n" +++ "import Bird\n\n" ++ + "config :: BirdConfig" +++ "config = def\n"+ mainFile a = "import Hack\n" ++ "import qualified Hack as Hack\n" ++@@ -69,7 +77,8 @@ "import Bird.Translator.Hack\n" ++ "import qualified Control.Monad.State as S\n" ++ "import qualified Control.Monad.Reader as R\n" ++- "import " ++ a ++ "\n" ++ "\n" +++ "import " ++ a ++ "\n" +++ "import " ++ a ++ ".Config\n\n" ++ "app :: Application\n" ++ "app = \\e -> route e\n" ++ "\n" ++@@ -79,7 +88,7 @@ " where \n" ++ " req = toBirdRequest e\n" ++ " response = do \n" ++- " reply <- runBirdResponder req matchRequest\n" +++ " reply <- (birdLogger config) req matchRequest\n" ++ " return $ fromBirdReply reply\n\n" ++ "matchRequest r = \n" ++
bird.cabal view
@@ -1,5 +1,5 @@ Name: bird-Version: 0.0.14+Version: 0.0.15 Build-type: Simple Synopsis: A simple, sinatra-inspired web framework. Description: Bird is a hack-compatible framework for simple websites.@@ -18,6 +18,6 @@ hs-source-dirs: bin library- build-depends: haskell98, mtl >= 1.1.0.2, process, containers, parsec >= 2.1.0.1, bytestring, base >= 4.0 && < 5, hack >= 2009.10.30, hack-handler-happstack, data-default >= 0.2, rallod - exposed-modules: Bird, Bird.Request, Bird.Reply, Bird.Request.QueryStringParser, Bird.BirdResponder, Bird.Translator, Bird.Translator.Hack+ build-depends: haskell98, MissingH >= 1.1.0.3, mtl >= 1.1.0.2, process, containers, parsec >= 2.1.0.1, bytestring, base >= 4.0 && < 5, hack >= 2009.10.30, hack-handler-happstack, data-default >= 0.2, rallod + exposed-modules: Bird, Bird.Logger, Bird.Config, Bird.Request, Bird.Reply, Bird.Request.QueryStringParser, Bird.BirdResponder, Bird.Translator, Bird.Translator.Hack hs-source-dirs: src/
readme.markdown view
@@ -54,6 +54,7 @@ get [] = do name <- param "name"+ log "I'm about to greet a Jedi. Teehee!" body $ "Greetings, " ++ (maybe "Jedi!" id name) now recompile your app and start it flying:@@ -106,11 +107,14 @@ -- creates/updates a header -- ex: get [] = body "Hello World" >> header "X-Powered-By" "BIRD!" + log :: String -> BirdResponder ()+ -- adds to the log+ -- ex: get [] = body "Hello World" >> log "Why did I just greet the world?"+ ## Notes This project is *still* in its infancy. Coming features: -* logging * post/put/delete http param processing * helpers for popular html generation solutions (Hamlet, HStringTemplate, HAXML, BlazeHTML, etc.) * WAI support
src/Bird.hs view
@@ -3,9 +3,13 @@ , module Bird.Reply , module Bird.Request , module Bird.BirdResponder+, module Bird.Logger+, module Bird.Config ) where import Data.Default import Bird.Reply import Bird.Request import Bird.BirdResponder+import Bird.Logger+import Bird.Config
src/Bird/BirdResponder.hs view
@@ -2,16 +2,17 @@ import Control.Monad.State import Control.Monad.Reader+import Control.Monad.Writer import Data.Default import Data.Maybe import Bird.Reply import Bird.Request import qualified Data.Map as Hash -type BirdResponder = StateT Reply (ReaderT Request IO)+type BirdResponder = StateT Reply (ReaderT Request (WriterT [String] IO)) runBirdResponder request router = - runReaderT (execStateT (router request) def) request+ runWriterT (runReaderT (execStateT (router request) def) request) body b = do reply <- get@@ -24,6 +25,9 @@ param paramName = do request <- ask return $ maybe Nothing id (lookup paramName $ params request)++log logMessage = do+ tell [logMessage] mime m = header "Content-Type" m
+ src/Bird/Config.hs view
@@ -0,0 +1,22 @@+module Bird.Config where ++import Data.Default+import Bird.Logger+import Bird.Request+import Bird.Reply+import Bird.BirdResponder++type Router = Request -> BirdResponder ()++data BirdConfig = + BirdConfig {+ staticDir :: String+ , birdLogger :: Request -> Router -> IO Reply+ }++instance Default BirdConfig where+ def = + BirdConfig {+ staticDir = "static"+ , birdLogger = defaultLogger+ }
+ src/Bird/Logger.hs view
@@ -0,0 +1,17 @@+module Bird.Logger where++import Bird.BirdResponder+import Bird.Reply+import Bird.Request+import Text.Printf+import qualified Data.String.Utils as StringUtils (join)+import System.CPUTime++defaultLogger request router = do+ let logPrelude = "\n" ++ (show $ verb request) ++ " " ++ (show $ rawRequestUri request)+ start <- getCPUTime+ (reply, logMessages) <- runBirdResponder request router + end <- getCPUTime+ let logEpilogue = (printf " Response code: %s" (show $ replyStatus reply)) ++ (printf "\n Response time: %0.3fs" (((fromIntegral (end - start)) / (10^12)) :: Double))+ putStrLn $ (StringUtils.join "\n" ([logPrelude] ++ logMessages ++ [logEpilogue])) ++ "\n"+ return reply
src/Bird/Request.hs view
@@ -11,10 +11,11 @@ data Request = Request { - verb :: RequestMethod- , path :: Path- , params :: [(String, Maybe String)]+ verb :: RequestMethod+ , path :: Path+ , params :: [(String, Maybe String)]+ , rawRequestUri :: String } deriving (Show) instance Default Request where- def = Request { verb = GET, path = [], params = [] }+ def = Request { verb = GET, path = [], params = [], rawRequestUri = "/" }
src/Bird/Translator/Hack.hs view
@@ -19,7 +19,7 @@ Hack.body = pack $ replyBody r } where- insertUnlessPresent _ oldValue = oldValue+ insertUnlessPresent = flip const instance BirdRequestTranslator Hack.Env where toBirdRequest e = @@ -27,7 +27,13 @@ verb = hackRequestMethodToBirdRequestMethod $ Hack.requestMethod e , path = split '/' $ Hack.pathInfo e , params = parseQueryString $ Hack.queryString e+ , rawRequestUri = (Hack.pathInfo e) ++ maybeQueryString e }+ where+ maybeQueryString e =+ if Hack.queryString e /= ""+ then "?" ++ Hack.queryString e+ else "" hackRequestMethodToBirdRequestMethod rm =