packages feed

loli 2009.6.29 → 2009.7.2

raw patch · 15 files changed

+168/−97 lines, 15 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Network.Loli.Engine: route :: RequestMethod -> String -> AppUnit -> Unit
- Network.Loli.Template.TextTemplate: render_TextTemplate :: String -> Context -> IO String
- Network.Loli.Type: type EnvFilter = Env -> Env
- Network.Loli.Type: type ResponseFilter = Response -> Response
+ Network.Loli.DSL: after :: (Response -> IO Response) -> Unit
+ Network.Loli.DSL: before :: (Env -> IO Env) -> Unit
+ Network.Loli.DSL: router :: Router -> Unit
+ Network.Loli.Engine: add_route_config :: RouteConfig -> Loli -> Loli
+ Network.Loli.Engine: set_router :: Router -> Loli -> Loli
+ Network.Loli.Middleware.IOConfig: ioconfig :: (Env -> IO Env) -> Middleware
+ Network.Loli.Template.TextTemplate: render_text_template :: String -> Context -> IO String
+ Network.Loli.Type: RouteConfig :: RoutePath -> Router -> RouteConfig
+ Network.Loli.Type: current_router :: Loli -> Router
+ Network.Loli.Type: data RouteConfig
+ Network.Loli.Type: route_path :: RouteConfig -> RoutePath
+ Network.Loli.Type: router :: RouteConfig -> Router
+ Network.Loli.Type: type Router = RouterT AppUnit
+ Network.Loli.Type: type RouterT a = String -> (a -> Application) -> RoutePathT a -> Middleware
- Network.Loli.Engine: add_route :: RoutePath -> Loli -> Loli
+ Network.Loli.Engine: add_route :: RequestMethod -> String -> AppUnit -> Unit
- Network.Loli.Middleware.LoliRouter: loli_router :: String -> (a -> Application) -> [RoutePathT a] -> Middleware
+ Network.Loli.Middleware.LoliRouter: loli_router :: String -> (a -> Application) -> RoutePathT a -> Middleware
- Network.Loli.Type: Loli :: [RoutePath] -> [Middleware] -> Assoc -> Loli
+ Network.Loli.Type: Loli :: Router -> [RouteConfig] -> [Middleware] -> Assoc -> Loli
- Network.Loli.Type: routes :: Loli -> [RoutePath]
+ Network.Loli.Type: routes :: Loli -> [RouteConfig]

Files

Nemesis view
@@ -15,9 +15,6 @@     sh "cabal configure"     sh "cabal sdist" -  desc "start console"-  task "i" (sh "ghci -isrc src/Test.hs")-   desc "put all .hs files in manifest"   task "manifest" $ do     sh "find . | grep 'hs$' > manifest"@@ -31,10 +28,12 @@    ghci "template" "Network/Loli/Template"   ghci "ipaste" "Test/LoliPaste"+  ghci "i" "Test/Test"      bin "test" "Test/Test"   bin "paste" "Test/LoliPaste"-  bin "myloli" "Test/myloli"+  bin "myapp" "Test/myapp"+  bin "debug" "Debug/Debug"         -- test
changelog.md view
@@ -1,14 +1,26 @@+2009.7.2+--------++### Features++* before / after filter+* On the fly router switcher++### Fix++* safari display weird header+ 2009.6.29 --------- -### Feature+### Features  * Initial hackage release  2009.6.27 --------- -### Feature+### Features  * add template * add local binding@@ -17,7 +29,7 @@ 2009.6.26 --------- -### Feature+### Features  * add route 
known-issues.md view
@@ -1,2 +1,1 @@-* safari display weird header info * unknown server socket error in LoliPaste.hs, it has something to do with unicode convertion, i.e. changing ls form MPSUTF8 to ls in MPS fix the problem, but encoding stays in utf-8 instead of plain unicode chars
loli.cabal view
@@ -1,5 +1,5 @@ Name:                 loli-Version:              2009.6.29+Version:              2009.7.2 Build-type:           Simple Synopsis:             A minimum web dev DSL in Haskell Description:@@ -25,6 +25,7 @@                       Network.Loli.Config                       Network.Loli.DSL                       Network.Loli.Engine+                      Network.Loli.Middleware.IOConfig                       Network.Loli.Middleware.LoliRouter                       Network.Loli.Middleware.UserMime                       Network.Loli.Template
readme.md view
@@ -6,7 +6,7 @@  First app -    -- myloli.hs+    -- myapp.hs          import Network.Loli     import Hack.Handler.Happstack@@ -19,15 +19,15 @@     cabal install loli     cabal install hack-handler-happstack     -    ghc --make myloli.hs-    ./myloli+    ghc --make myapp.hs+    ./myapp  check: <http://localhost:3000>   ## Routes -### Verb+### Verbs      get "/" $ do       -- something for a get request@@ -40,6 +40,7 @@          delete "/" $ do       -- ..+ ### Captures      get "/say/:user/:message" $ do@@ -51,7 +52,7 @@  ## Static -    -- public serve, only allows /src+    -- public serve, only allows `./src`     public (Just ".") ["/src"]  ## Views root@@ -65,7 +66,6 @@      import Network.Loli.Template.TextTemplate     -    -- template     get "/hi/:user" $ output (text_template "hello.html")          -- in hello.html@@ -137,6 +137,22 @@     -- treat .hs extension as text/plain     mime "hs" "text/plain" +## Filters++    -- before takes a function of type (Env -> IO Env)+    before $ \e -> do+      putStrLn "before called"+      return e+    +    -- after takes that of type (Response -> IO Response)+    after return++## On the fly router switcher++The router can be switched at any time, it will effect any route path that follows.+    +    router loli_router+ ## Hack integration  ### Use hack middleware@@ -155,4 +171,8 @@  ## Note -If you see this, use the git version!+use the git version ...++## Reference++* loli is inspired by [Rack](http://rack.rubyforge.org), [Rails](http://rubyonrails.org), [Ramaze](http://ramaze.net), [Happstack](http://happstack.com/) and [Sinatra](http://www.sinatrarb.com/).
src/Network/Loli/Config.hs view
@@ -18,32 +18,28 @@   where     set_view_root env =       let hack_headers = env.hackHeaders-          pre_config = [(loli_config ++ loli_views, loli_default_views)]+          pre_config   = [(loli_config ++ loli_views, loli_default_views)]       in       env {hackHeaders = hack_headers ++ pre_config}     default_content_type :: String     default_content_type = "text/plain; charset=UTF-8"-    -loli_captures :: String-loli_captures = "loli-captures-" -loli_locals :: String-loli_locals = "loli-locals-" -loli_partials :: String-loli_partials = "loli-partials-" -loli_config :: String-loli_config = "loli-config-"--loli_layout :: String-loli_layout = "layout"--loli_views :: String-loli_views = "views"--loli_default_views :: String-loli_default_views = "views"-+loli_captures       :: String+loli_locals         :: String+loli_partials       :: String+loli_config         :: String+loli_layout         :: String+loli_views          :: String+loli_default_views  :: String loli_layout_content :: String++loli_captures       = "loli-captures-"+loli_locals         = "loli-locals-"+loli_partials       = "loli-partials-"+loli_config         = "loli-config-"+loli_layout         = "layout"+loli_views          = "views"+loli_default_views  = "views" loli_layout_content = "content"
src/Network/Loli/DSL.hs view
@@ -3,11 +3,13 @@ import Control.Monad.Reader import Control.Monad.State import Hack+import Hack.Contrib.Middleware.Censor import Hack.Contrib.Middleware.Config import Hack.Contrib.Middleware.Static import MPS import Network.Loli.Config import Network.Loli.Engine+import Network.Loli.Middleware.IOConfig import Network.Loli.Type import Network.Loli.Utils import Prelude hiding ((.), (>), (^))@@ -24,14 +26,24 @@ views :: String -> Unit views x = middleware $ config (set_namespace loli_config loli_views x) -get, put, delete, post :: String -> AppUnit -> Unit-get    = route GET-put    = route PUT-delete = route DELETE-post   = route POST+router :: Router -> Unit+router = set_router > update +get, put, post, delete :: String -> AppUnit -> Unit+get    = add_route GET+put    = add_route PUT+post   = add_route POST+delete = add_route DELETE++ middleware :: Middleware -> Unit-middleware x = add_middleware x .update+middleware = add_middleware > update++before :: (Env -> IO Env) -> Unit+before = ioconfig > middleware++after :: (Response -> IO Response) -> Unit+after = censor > middleware  mime :: String -> String -> Unit mime k v = add_mime k v .update
src/Network/Loli/Engine.hs view
@@ -17,28 +17,34 @@ import Prelude hiding ((.), (/), (>), (^))  run_app :: AppUnit -> Application-run_app unit = \env -> runReaderT unit env .flip execStateT def+run_app unit = \env -> runReaderT unit env .flip execStateT def {status = 200}  loli :: Unit -> Application loli unit = run unit (not_found empty_app)   where+    run_route x = (x.router) loli_captures run_app (x.route_path)+         run :: Unit -> Middleware     run unit' = -      let loli_state  = execState unit' def-          paths       = loli_state.routes-          -          loli_app    = loli_router loli_captures run_app paths -          mime_filter = user_mime (loli_state.mimes)-          stack       = loli_state.middlewares.use-          pre         = pre_installed_middlewares.use+      let loli_state    = execState unit' def+          route_configs = loli_state.routes+          route         = route_configs.map run_route .use+          mime_filter   = user_mime (loli_state.mimes)+          stack         = loli_state.middlewares.use+          pre           = pre_installed_middlewares.use       in-      use [pre, mime_filter, stack, loli_app]+      use [pre, mime_filter, stack, route] -add_route :: RoutePath -> Loli -> Loli-add_route r s = let xs = s.routes in s {routes = xs.insert_last r}+add_route_config :: RouteConfig -> Loli -> Loli+add_route_config r s = let xs = s.routes in s {routes = xs.insert_last r} -route :: RequestMethod -> String -> AppUnit -> Unit-route r s u = update $ add_route (r, s, u)+add_route :: RequestMethod -> String -> AppUnit -> Unit+add_route r s u = do+  c <- get ^ current_router+  update $ add_route_config RouteConfig { route_path = (r, s, u), router = c }++set_router :: Router -> Loli -> Loli+set_router r x = x { current_router = r }  add_middleware :: Middleware -> Loli -> Loli add_middleware x s = 
+ src/Network/Loli/Middleware/IOConfig.hs view
@@ -0,0 +1,6 @@+module Network.Loli.Middleware.IOConfig (ioconfig) where++import Hack++ioconfig :: (Env -> IO Env) -> Middleware+ioconfig before app = \env -> before env >>= app
src/Network/Loli/Middleware/LoliRouter.hs view
@@ -1,6 +1,5 @@ module Network.Loli.Middleware.LoliRouter (loli_router) where -import Data.List (find) import Data.Maybe import Hack import Hack.Contrib.Utils@@ -9,22 +8,24 @@ import Prelude hiding ((.), (>), (/))  -type RoutePathT a   = (RequestMethod, String, a)-type Assoc          = [(String, String)]+type RoutePathT a = (RequestMethod, String, a)+type Assoc        = [(String, String)] -loli_router :: String -> (a -> Application) -> [RoutePathT a] -> Middleware-loli_router prefix runner h app' = \env'' ->-  let path             = env''.path_info-      script           = env''.script_name-      mod_env location = env'' ++loli_router :: String -> (a -> Application) -> RoutePathT a -> Middleware+loli_router prefix runner route_path app' = \env ->+  let path             = env.path_info+      script           = env.script_name+      mod_env location = env          { scriptName  = script ++ location         , pathInfo    = path.drop (location.length)         }   in-  case h.find (match_route env'') of-    Nothing -> app' env''-    Just (_, template, app_state) -> do-      let (location, params) = parse_params template path .fromJust+  if route_path.match_route env.not+    then app' env+    else do+      let (_, template, app_state) = route_path+          (location, params) = parse_params template path .fromJust       runner app_state (mod_env location .merge_captured params)   where     match_route env' (method, template, _) = @@ -35,13 +36,14 @@   parse_params :: String -> String -> Maybe (String, Assoc)-parse_params "" ""   = Just ("", [])-parse_params "" _    = Nothing+parse_params "" ""  = Just ("", [])+parse_params "" _   = Nothing parse_params "/" "" = Nothing-parse_params "/" _ = Just ("/", [])-parse_params t s =+parse_params "/" _  = Just ("/", [])++parse_params t s =    let template_tokens = t.split "/"-      url_tokens = s.split "/"+      url_tokens      = s.split "/"   in   if url_tokens.length < template_tokens.length     then Nothing@@ -50,9 +52,10 @@       in       if rs.all isJust         then -          let location = "/" / url_tokens.take (template_tokens.length).join "/"+          let token_length = template_tokens.length+              location     = "/" / url_tokens.take token_length .join "/"           in-          Just $ (location, rs.map fromJust.filter isJust.map fromJust)+          Just $ (location, rs.catMaybes.catMaybes)         else Nothing      where@@ -64,8 +67,8 @@ -- copy from loli utils put_namespace :: String -> Assoc -> Env -> Env put_namespace x xs env = -  let adds = xs.map_fst (x ++)-      new_headers = adds.map fst+  let adds             = xs.map_fst (x ++)+      new_headers      = adds.map fst       new_hack_headers =          env.custom.reject (fst > belongs_to new_headers) ++ adds   in
src/Network/Loli/Template.hs view
@@ -35,9 +35,9 @@ template_locals :: AppUnitT Context template_locals = do   c <- captures-  b <- locals+  l <- locals   p <- partial_locals-  return (c ++ b ++ p)+  return (c ++ l ++ p)  render :: (Template a) => a -> AppUnitT String render x = do
src/Network/Loli/Template/TextTemplate.hs view
@@ -8,8 +8,8 @@ import Text.Template hiding (Context, Template, template) import qualified Text.Template as T -render_TextTemplate :: String -> Context -> IO String-render_TextTemplate x c = +render_text_template :: String -> Context -> IO String+render_text_template x c =    readTemplate (x.u2b) ^ flip T.render (create_context c) ^ toString   where     create_context = map (fromString *** fromString) > to_h@@ -17,7 +17,7 @@ data TextTemplate = TextTemplate String  instance Template TextTemplate where-  interpolate (TextTemplate x) r = render_TextTemplate (r / x)+  interpolate (TextTemplate x) r = render_text_template (r / x)  text_template :: String -> TextTemplate text_template = TextTemplate
src/Network/Loli/Type.hs view
@@ -5,28 +5,37 @@ import Data.Default import Hack import Hack.Contrib.Utils+import Network.Loli.Middleware.LoliRouter -type RoutePathT a   = (RequestMethod, String, a)-type RoutePath      = RoutePathT AppUnit-type EnvFilter      = Env -> Env-type ResponseFilter = Response -> Response-type Assoc          = [(String, String)]-type AppState       = Response-type AppReader      = Env+type RoutePathT a = (RequestMethod, String, a)+type RoutePath    = RoutePathT AppUnit+type AppReader    = Env+type AppState     = Response+type AppUnitT     = ReaderT AppReader (StateT AppState IO)+type AppUnit      = AppUnitT ()+type Assoc        = [(String, String)]+type Context      = Assoc -type AppUnitT       = ReaderT AppReader (StateT AppState IO)-type AppUnit        = AppUnitT ()-type Context        = Assoc+type RouterT a = String -> (a -> Application) -> RoutePathT a -> Middleware+type Router    = RouterT AppUnit +data RouteConfig = RouteConfig+  {+    route_path :: RoutePath+  , router     :: Router+  }+ data Loli = Loli   {-    routes :: [RoutePath]-  , middlewares :: [Middleware]-  , mimes :: Assoc+    current_router  :: Router+  , routes          :: [RouteConfig]+  , middlewares     :: [Middleware]+  , mimes           :: Assoc   } + instance Default Loli where-  def = Loli def [dummy_middleware] def+  def = Loli loli_router def [dummy_middleware] def   type UnitT a = State Loli a
src/Network/Loli/Utils.hs view
@@ -15,8 +15,8 @@  put_namespace :: String -> [(String, String)] -> Env -> Env put_namespace x xs env = -  let adds = xs.map_fst (x ++)-      new_headers = adds.map fst+  let adds             = xs.map_fst (x ++)+      new_headers      = adds.map fst       new_hack_headers =          env.custom.reject (fst > belongs_to new_headers) ++ adds   in
src/Test/Test.hs view
@@ -8,6 +8,7 @@ import Network.Loli.Template.ConstTemplate (const_template) import Network.Loli.Template.TextTemplate import Network.Loli.Utils+import Network.Loli.Middleware.LoliRouter import Data.Maybe import MPS ((^)) import Prelude hiding ((^))@@ -15,14 +16,21 @@  -- default on port 3000 +main :: IO () main = run . loli $ do        middleware lambda     middleware show_status+    +    before return+    after return      get "/bench"     $ do       name <- ask ^ params ^ lookup "name" ^ fromMaybe "nobody"       html ("<h1>" ++ name ++ "</h1>")++    -- on the fly router switcher+    router loli_router      -- simple     get "/hello"    (text "hello world")