transformations 0.1.1.0 → 0.2.0.0
raw patch · 127 files changed
+50526/−3676 lines, 127 filesdep +QuickCheckdep +criteriondep −rewritingdep −zipperdep ~basedep ~regulardep ~template-haskellsetup-changednew-component:exe:Benchmark
Dependencies added: QuickCheck, criterion
Dependencies removed: rewriting, zipper
Dependency ranges changed: base, regular, template-haskell
Files
- Generics/MultiRec/Any.hs +0/−17
- Generics/MultiRec/CountIs.hs +36/−0
- Generics/MultiRec/HZip.hs +0/−76
- Generics/MultiRec/LR.hs +0/−94
- Generics/MultiRec/Ord.hs +0/−57
- Generics/MultiRec/Rewriting.hs +0/−7
- Generics/MultiRec/Rewriting/Machinery.hs +0/−66
- Generics/MultiRec/Rewriting/Rules.hs +0/−100
- Generics/MultiRec/ShallowEq.hs +48/−0
- Generics/MultiRec/Transformations/Children.hs +80/−0
- Generics/MultiRec/Transformations/Explicit.hs +0/−442
- Generics/MultiRec/Transformations/Main.hs +190/−0
- Generics/MultiRec/Transformations/MemoTable.hs +165/−0
- Generics/MultiRec/Transformations/Path.hs +250/−0
- Generics/MultiRec/Transformations/RewriteRules.hs +0/−59
- Generics/MultiRec/Transformations/TH.hs +0/−241
- Generics/MultiRec/Transformations/ZipChildren.hs +94/−0
- Generics/MultiRec/Transformations/ZipperState.hs +0/−72
- Generics/MultiRec/Zipper.hs +220/−0
- Generics/Regular/Functions/GOrd.hs +41/−41
- Generics/Regular/Transformations/Explicit.hs +0/−357
- Generics/Regular/Transformations/Main.hs +451/−0
- Generics/Regular/Transformations/RewriteRules.hs +0/−31
- Generics/Regular/Transformations/TH.hs +0/−191
- Generics/Regular/Transformations/ZipperState.hs +0/−57
- Generics/Regular/Zipper.hs +244/−245
- LICENSE +675/−675
- QuickCheck.hs +105/−0
- README +24/−0
- Setup.hs +2/−2
- examples/Datatypes.hs +81/−81
- examples/Expr.hs +58/−0
- examples/LUA.hs +715/−0
- examples/LUA_project/application.lua.1 +733/−0
- examples/LUA_project/application.lua.10 +655/−0
- examples/LUA_project/application.lua.11 +655/−0
- examples/LUA_project/application.lua.12 +652/−0
- examples/LUA_project/application.lua.13 +649/−0
- examples/LUA_project/application.lua.14 +645/−0
- examples/LUA_project/application.lua.15 +659/−0
- examples/LUA_project/application.lua.16 +659/−0
- examples/LUA_project/application.lua.17 +659/−0
- examples/LUA_project/application.lua.18 +659/−0
- examples/LUA_project/application.lua.19 +655/−0
- examples/LUA_project/application.lua.2 +724/−0
- examples/LUA_project/application.lua.20 +597/−0
- examples/LUA_project/application.lua.21 +578/−0
- examples/LUA_project/application.lua.22 +580/−0
- examples/LUA_project/application.lua.23 +580/−0
- examples/LUA_project/application.lua.24 +575/−0
- examples/LUA_project/application.lua.25 +564/−0
- examples/LUA_project/application.lua.26 +561/−0
- examples/LUA_project/application.lua.27 +545/−0
- examples/LUA_project/application.lua.28 +545/−0
- examples/LUA_project/application.lua.29 +559/−0
- examples/LUA_project/application.lua.3 +708/−0
- examples/LUA_project/application.lua.30 +546/−0
- examples/LUA_project/application.lua.31 +546/−0
- examples/LUA_project/application.lua.32 +556/−0
- examples/LUA_project/application.lua.33 +558/−0
- examples/LUA_project/application.lua.34 +570/−0
- examples/LUA_project/application.lua.35 +600/−0
- examples/LUA_project/application.lua.36 +600/−0
- examples/LUA_project/application.lua.37 +600/−0
- examples/LUA_project/application.lua.38 +589/−0
- examples/LUA_project/application.lua.39 +575/−0
- examples/LUA_project/application.lua.4 +706/−0
- examples/LUA_project/application.lua.40 +575/−0
- examples/LUA_project/application.lua.41 +572/−0
- examples/LUA_project/application.lua.42 +577/−0
- examples/LUA_project/application.lua.43 +554/−0
- examples/LUA_project/application.lua.44 +527/−0
- examples/LUA_project/application.lua.45 +527/−0
- examples/LUA_project/application.lua.46 +525/−0
- examples/LUA_project/application.lua.47 +525/−0
- examples/LUA_project/application.lua.48 +522/−0
- examples/LUA_project/application.lua.49 +520/−0
- examples/LUA_project/application.lua.5 +694/−0
- examples/LUA_project/application.lua.50 +516/−0
- examples/LUA_project/application.lua.51 +516/−0
- examples/LUA_project/application.lua.52 +514/−0
- examples/LUA_project/application.lua.53 +502/−0
- examples/LUA_project/application.lua.54 +502/−0
- examples/LUA_project/application.lua.55 +498/−0
- examples/LUA_project/application.lua.56 +495/−0
- examples/LUA_project/application.lua.57 +496/−0
- examples/LUA_project/application.lua.58 +495/−0
- examples/LUA_project/application.lua.59 +495/−0
- examples/LUA_project/application.lua.6 +692/−0
- examples/LUA_project/application.lua.60 +486/−0
- examples/LUA_project/application.lua.61 +482/−0
- examples/LUA_project/application.lua.62 +481/−0
- examples/LUA_project/application.lua.63 +480/−0
- examples/LUA_project/application.lua.64 +473/−0
- examples/LUA_project/application.lua.65 +470/−0
- examples/LUA_project/application.lua.66 +463/−0
- examples/LUA_project/application.lua.67 +457/−0
- examples/LUA_project/application.lua.68 +453/−0
- examples/LUA_project/application.lua.69 +436/−0
- examples/LUA_project/application.lua.7 +658/−0
- examples/LUA_project/application.lua.70 +436/−0
- examples/LUA_project/application.lua.71 +439/−0
- examples/LUA_project/application.lua.72 +421/−0
- examples/LUA_project/application.lua.73 +417/−0
- examples/LUA_project/application.lua.74 +411/−0
- examples/LUA_project/application.lua.75 +375/−0
- examples/LUA_project/application.lua.76 +358/−0
- examples/LUA_project/application.lua.77 +357/−0
- examples/LUA_project/application.lua.78 +331/−0
- examples/LUA_project/application.lua.79 +331/−0
- examples/LUA_project/application.lua.8 +658/−0
- examples/LUA_project/application.lua.80 +330/−0
- examples/LUA_project/application.lua.81 +345/−0
- examples/LUA_project/application.lua.82 +328/−0
- examples/LUA_project/application.lua.83 +317/−0
- examples/LUA_project/application.lua.84 +306/−0
- examples/LUA_project/application.lua.85 +276/−0
- examples/LUA_project/application.lua.86 +264/−0
- examples/LUA_project/application.lua.87 +254/−0
- examples/LUA_project/application.lua.88 +248/−0
- examples/LUA_project/application.lua.89 +211/−0
- examples/LUA_project/application.lua.9 +656/−0
- examples/LUA_project/application.lua.90 +209/−0
- examples/Lang.lhs +367/−367
- examples/MultiRec.hs +120/−129
- examples/Regular.hs +118/−212
- transformations.cabal +144/−57
− Generics/MultiRec/Any.hs
@@ -1,17 +0,0 @@-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE GADTs #-}--module Generics.MultiRec.Any where--import Generics.MultiRec--data Any phi where- Any :: phi ix -> ix -> Any phi---- | Unify an 'Any' with an @a@.-matchAny :: forall phi ix. EqS phi => phi ix -> Any phi -> Maybe ix-matchAny p (Any w x) = match' w x p where- match' :: EqS s => s b -> b -> s a -> Maybe a- match' w x w' = case eqS w w' of- Nothing -> Nothing- Just Refl -> Just x
+ Generics/MultiRec/CountIs.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Generics.MultiRec.CountIs where + +import Generics.MultiRec + +-------------------------------------------------------------------------------- +-- Count I's (for showing) +-------------------------------------------------------------------------------- + +class CountIs (f :: (* -> *) -> * -> *) where + countIs :: f r ix -> Int + +instance CountIs (I ix) where countIs _ = 1 +instance CountIs (t :.: f) where countIs _ = 1 +instance CountIs (K a) where countIs _ = 0 +instance CountIs U where countIs _ = 0 + +instance (CountIs f) => CountIs (C c f) where + countIs (_ :: C c f r ix) = countIs (undefined :: f r ix) +instance (CountIs f) => CountIs (f :>: ix) where + countIs (_ :: (f :>: ix) r xi) = countIs (undefined :: f r ix) + +instance (CountIs f, CountIs g) => CountIs (f :+: g) where + countIs (L x) = countIs x + countIs (R x) = countIs x + +instance (CountIs f, CountIs g) => CountIs (f :*: g) where + countIs (_ :: (f :*: g) r ix) = countIs (undefined :: f r ix) + + countIs (undefined :: g r ix)
− Generics/MultiRec/HZip.hs
@@ -1,76 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE GADTs #-}--module Generics.MultiRec.HZip where--import Generics.MultiRec-import Control.Monad (liftM, liftM2, zipWithM)--class HZip phi f where- hzipM :: Monad m =>- (forall ix. El phi ix => phi ix -> r ix -> r' ix -> m (r'' ix)) ->- f r ix -> f r' ix -> m (f r'' ix)--instance El phi xi => HZip phi (I xi) where- hzipM f (I x) (I y) = liftM I (f proof x y)--instance Eq a => HZip phi (K a) where- hzipM f (K x) (K y) | x == y = return (K x)- | otherwise = fail "zip failed in K"--instance HZip phi U where- hzipM f U U = return U--instance (HZip phi a, HZip phi b) => HZip phi (a :+: b) where- hzipM f (L x) (L y) = liftM L (hzipM f x y)- hzipM f (R x) (R y) = liftM R (hzipM f x y)- hzipM f _ _ = fail "zip failed"--instance (HZip phi a, HZip phi b) => HZip phi (a :*: b) where- hzipM f (x1 :*: y1) (x2 :*: y2) = liftM2 (:*:) (hzipM f x1 x2) (hzipM f y1 y2)--instance HZip phi f => HZip phi (f :>: xi) where- hzipM f (Tag x) (Tag y) = liftM Tag (hzipM f x y)--instance HZip phi f => HZip phi (C c f) where- hzipM f (C x) (C y) = liftM C (hzipM f x y)--instance HZip phi f => HZip phi ([] :.: f) where- hzipM f (D x) (D y) = liftM D (zipWithM (hzipM f) x y)---- | Monadic zip but argument is not monadic-hzip :: (HZip phi f, Monad m) =>- (forall ix. El phi ix => phi ix -> r ix -> s ix -> t ix) ->- phi ix -> f r ix -> f s ix -> m (f t ix)-hzip f p = hzipM (\w x y -> return (f w x y))---- | Unsafe zip-hzip' :: (HZip phi f) =>- (forall ix. El phi ix => phi ix -> r ix -> s ix -> t ix) ->- phi ix -> f r ix -> f s ix -> f t ix-hzip' f p a b = case hzip (\p x y -> f p x y) p a b of- Nothing -> error "generic zip failed"- Just res -> res---- | Combine two structures monadically only-combine :: forall phi f r r' m ix. (Monad m, HZip phi f) =>- (forall ix. El phi ix => phi ix -> r ix -> r' ix -> m ()) ->- phi ix -> f r ix -> f r' ix -> m ()-combine f l x y = hzipM wrapf x y >> return ()- where- wrapf :: forall ix' b. El phi ix' => phi ix' -> r ix' -> r' ix' -> m (K0 () b)- wrapf ix x y = f ix x y >> return (K0 ())---- | Generic equality-geq :: (Fam phi, HZip phi (PF phi)) => phi ix -> ix -> ix -> Bool-geq ix x y = maybe False (const True) (geq' ix (I0 x) (I0 y))---- | Monadic generic equality (just for the sake of the monad!)-geq' :: (Monad m, Fam phi, HZip phi (PF phi))- => phi ix -> I0 ix -> I0 ix -> m ()-geq' p (I0 x) (I0 y) = combine geq' p (from p x) (from p y)
− Generics/MultiRec/LR.hs
@@ -1,94 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE GADTs #-}--module Generics.MultiRec.LR where--import Generics.MultiRec---------------------------------------------------------------------------------- Functions for generating values that are different on top-level.---------------------------------------------------------------------------------- | The @LRBase@ class defines two functions, @leftb@ and @rightb@, which --- should produce different values.-class LRBase a where- leftb :: a- rightb :: a--instance LRBase Int where- leftb = 0- rightb = 1--instance LRBase Integer where- leftb = 0- rightb = 1--instance LRBase Char where- leftb = 'L'- rightb = 'R'- -instance LRBase Bool where- leftb = True- rightb = False--instance LRBase a => LRBase [a] where- leftb = []- rightb = [rightb]---- | The @LR@ class defines two functions, @leftf@ and @rightf@, which should --- produce different functorial values.-class LR phi (f :: (* -> *) -> * -> *) where--- leftf :: s ix -> (forall ix . Ix s ix => s ix -> r ix) -> [f s r ix]- leftf :: phi ix -> (forall ix'. El phi ix' => phi ix' -> r ix') -> [f r ix]- rightf :: phi ix -> (forall ix'. El phi ix' => phi ix' -> r ix') -> [f r ix]- -instance El phi xi => LR phi (I xi) where- leftf _ f = [I (f proof)]- rightf _ f = [I (f proof)]--instance LRBase a => LR phi (K a) where- leftf _ _ = [K leftb]- rightf _ _ = [K rightb]--instance LR phi U where- leftf _ _ = [U]- rightf _ _ = [U]--instance (LR phi f, LR phi g) => LR phi (f :+: g) where- leftf p f = map L (leftf p f) ++ map R (leftf p f)- rightf p f = map R (rightf p f) ++ map L (rightf p f)--instance (LR phi f, LR phi g) => LR phi (f :*: g) where- leftf p f = zipWith (:*:) (leftf p f) (leftf p f)- rightf p f = zipWith (:*:) (rightf p f) (rightf p f)--instance LR phi f => LR phi (C c f) where- leftf p f = map C (leftf p f)- rightf p f = map C (rightf p f)--instance (El phi ix, LR phi f, EqS phi) => LR phi (f :>: ix) where- leftf p f = case eqS (proof :: phi ix) p of- Just Refl -> map Tag (leftf p f)- Nothing -> []- rightf p f = case eqS (proof :: phi ix) p of- Just Refl -> map Tag (rightf p f)- Nothing -> []--instance LR phi f => LR phi ([] :.: f) where- leftf p f = [D []]- rightf p f = map (\v -> D [v]) $ rightf p f--left :: (Fam phi, LR phi (PF phi)) => phi ix -> ix-left p = to p $ safeHead $ leftf p (I0 . left)--right :: (Fam phi, LR phi (PF phi)) => phi ix -> ix-right p = to p $ safeHead $ rightf p (I0 . right)--safeHead [] = error "Internal error, left or right returned []"-safeHead (x:xs) = x
− Generics/MultiRec/Ord.hs
@@ -1,57 +0,0 @@-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}--module Generics.MultiRec.Ord where--import Generics.MultiRec-import Data.Monoid (mappend)------------------------------------------------------------------------------------- Generic Ord----------------------------------------------------------------------------------class HOrd phi f where- hcompare :: (forall ix. phi ix -> r ix -> r ix -> Ordering) - -> phi ix -> f r ix -> f r ix -> Ordering--instance El phi xi => HOrd phi (I xi) where- hcompare f _ (I x) (I y) = f proof x y--instance Ord a => HOrd phi (K a) where- hcompare _ _ (K x) (K y) = compare x y--instance HOrd phi U where- hcompare _ _ U U = EQ--instance (HOrd phi f, HOrd phi g) => HOrd phi (f :+: g) where- hcompare f p (L _) (R _) = LT- hcompare f p (R _) (L _) = GT- hcompare f p (L x) (L y) = hcompare f p x y- hcompare f p (R x) (R y) = hcompare f p x y--instance (HOrd phi f, HOrd phi g) => HOrd phi (f :*: g) where- hcompare f p (v :*: x) (w :*: y) = hcompare f p v w `mappend` hcompare f p x y--instance HOrd phi f => HOrd phi (C c f) where- hcompare f p (C x) (C y) = hcompare f p x y--instance HOrd phi f => HOrd phi (f :>: ix) where- hcompare f p (Tag x) (Tag y) = hcompare f p x y--instance (Ord1 f, HOrd phi g) => HOrd phi (f :.: g) where- hcompare f p (D x) (D y) = compare1 (hcompare f p) x y--class Ord1 f where- compare1 :: (a -> a -> Ordering) -> f a -> f a -> Ordering--instance Ord1 [] where- compare1 f [] [] = EQ- compare1 f [] _ = LT- compare1 f _ [] = GT- compare1 f (x:xs) (y:ys) = f x y `mappend` compare1 f xs ys--gcompare :: (Fam phi, HOrd phi (PF phi)) => phi ix -> ix -> ix -> Ordering-gcompare p x1 x2 = hcompare (\ p (I0 x1) (I0 x2) -> gcompare p x1 x2) p (from p x1) (from p x2)
− Generics/MultiRec/Rewriting.hs
@@ -1,7 +0,0 @@-module Generics.MultiRec.Rewriting (- module Generics.MultiRec.Rewriting.Machinery,- module Generics.MultiRec.Rewriting.Rules,-) where--import Generics.MultiRec.Rewriting.Machinery-import Generics.MultiRec.Rewriting.Rules
− Generics/MultiRec/Rewriting/Machinery.hs
@@ -1,66 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE GADTs #-}--module Generics.MultiRec.Rewriting.Machinery where--import Generics.MultiRec-import Generics.MultiRec.HZip-import Generics.MultiRec.Rewriting.Rules-import Generics.MultiRec.Any--import qualified Data.Map as M-import Control.Monad.State---------------------------------------------------------------------------------- Class synonym for shorter names-------------------------------------------------------------------------------class (Fam phi, EqS phi, HZip phi (PF phi), HFunctor phi (PF phi))- => Rewrite phi---------------------------------------------------------------------------------- Actual rewriting-------------------------------------------------------------------------------rewriteM :: Rewrite phi => Rule phi a -> a -> Maybe a-rewriteM (Rule p (lhs :~> rhs)) term = - match p lhs term >>= return . (\s -> inst s p rhs)--match :: (Monad m, Rewrite phi) => - phi ix -> Scheme phi ix -> ix -> m (Subst phi)-match p pat term = execStateT (matchM p pat (I0 term)) M.empty--matchM :: (Monad m, Rewrite phi) - => phi ix -> Scheme phi ix -> I0 ix -> StateT (Subst phi) m ()-matchM p scheme (I0 e) = case scheme of- HIn (L (K var)) -> do - subst <- get- case M.lookup var subst of- Nothing -> put (M.insert var (Any p e) subst)- Just exTerm -> checkEqual p e exTerm- HIn (R r) -> combine matchM p r (from p e)--checkEqual :: (Monad m, Rewrite phi)- => phi ix -> ix -> Any phi -> m ()-checkEqual p e (Any p' e') = case eqS p p' of- Nothing -> fail "checkEqual"- Just Refl -> geq' p (I0 e) (I0 e')--inst :: Rewrite phi =>- Subst phi -> phi ix -> Scheme phi ix -> ix-inst s ix p- = case p of- HIn (L (K x)) ->- case M.lookup x s of- Just (Any ix' e)- -> case eqS ix ix' of- Just Refl -> e- Nothing -> error "Coerce error in inst"- HIn (R r) -> to ix $ hmap (\ix' -> I0 . inst s ix') ix r--type Subst phi = M.Map Metavar (Any phi)
− Generics/MultiRec/Rewriting/Rules.hs
@@ -1,100 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE GADTs #-}--module Generics.MultiRec.Rewriting.Rules where--import Generics.MultiRec-import Generics.MultiRec.LR-import Generics.MultiRec.HZip---------------------------------------------------------------------------------- Rule specification.---------------------------------------------------------------------------------- | Specifies a rule as a value of a datatype.-infix 5 :~>-data RuleSpec a = a :~> a---- | Returns the left-hand side of a rule.-lhsR :: RuleSpec a -> a-lhsR (x :~> _) = x---- | Returns the right-hand side of a rule.-rhsR :: RuleSpec a -> a-rhsR (_ :~> y) = y---------------------------------------------------------------------------------- Representation of a rule.--------------------------------------------------------------------------------- | Extends a pattern functor with a case for a metavariable.-type Ext phi = K Metavar :+: PF phi-type Metavar = Int---- | Recursively extends a type with a case for a metavariable.-type Scheme phi = HFix (Ext phi)---- | Allows metavariables on either side of a rule.-data Rule phi a where - Rule :: phi ix -> RuleSpec (Scheme phi ix) -> Rule phi ix---- | Constructs a metavariable.-metavar :: phi ix -> Metavar -> Scheme phi ix-metavar _ = HIn . L . K--pf :: phi ix -> PF phi (Scheme phi) ix -> Scheme phi ix-pf _ = HIn . R---------------------------------------------------------------------------------- Builder for transforming a rule specification to a rule.--------------------------------------------------------------------------------class Builder phi a where- type Target a :: *- base :: phi (Target a) -> a -> RuleSpec (Target a)- diag :: phi (Target a) -> a -> [RuleSpec (Target a)]--instance Builder phi (RuleSpec a) where- type Target (RuleSpec a) = a- base _ x = x- diag _ x = [x]--instance (Builder phi a, Fam phi, LR phi (PF phi), El phi b)- => Builder phi (b -> a) where- type Target (b -> a) = Target a- base ix f = base ix (f (left (proof :: phi b)))- diag ix f = base ix (f (right (proof :: phi b))) :- diag ix (f (left (proof :: phi b)))--rule :: forall phi r. (Fam phi, Builder phi r, HZip phi (PF phi), - El phi (Target r), EqS phi, HFunctor phi (PF phi))- => r -> Rule phi (Target r)-rule f = Rule ix $ foldr1 mergeRules rules- where- ix = proof :: phi (Target r)- mergeRules x y = - mergeSchemes ix (lhsR x) (lhsR y) :~>- mergeSchemes ix (rhsR x) (rhsR y)- rules = zipWith (ins (base ix f)) (diag ix f) [0..] - ins x y v = - insertMVar v ix (I0 (lhsR x)) (I0 (lhsR y)) :~>- insertMVar v ix (I0 (rhsR x)) (I0 (rhsR y))--mergeSchemes :: HZip phi (PF phi)- => phi ix -> Scheme phi ix -> Scheme phi ix -> Scheme phi ix-mergeSchemes p a@(HIn x) b@(HIn y) = case (x,y) of- (L _,_) -> a- (_,L _) -> b- _ -> HIn (hzip' mergeSchemes p x y)--insertMVar :: forall phi ix. (Fam phi, HZip phi (PF phi), El phi ix)- => Metavar -> phi ix -> I0 ix -> I0 ix -> Scheme phi ix-insertMVar name p (I0 x) (I0 y) =- case hzip (insertMVar name) p (from p x) (from p y) of- Just struc -> pf p struc- Nothing -> metavar p name
+ Generics/MultiRec/ShallowEq.hs view
@@ -0,0 +1,48 @@+{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Generics.MultiRec.ShallowEq where + +import Generics.MultiRec +import Data.Foldable ( toList ) +import Data.Traversable ( Traversable ) + +-------------------------------------------------------------------------------- +-- Shallow equality +-------------------------------------------------------------------------------- + +class SEq phi (f :: (* -> *) -> * -> *) where + shallowEq :: phi ix -> f r ix -> f r ix -> Bool + +instance SEq phi (I xi) where + shallowEq _ _ _ = True + +instance SEq phi U where + shallowEq _ _ _ = True + +instance Eq a => SEq phi (K a) where + shallowEq p (K a) (K b) = a == b + +instance (SEq phi f, SEq phi g) => SEq phi (f :+: g) where + shallowEq p (L a) (L b) = shallowEq p a b + shallowEq p (R a) (R b) = shallowEq p a b + shallowEq _ _ _ = False + +instance (SEq phi f, SEq phi g) => SEq phi (f :*: g) where + shallowEq p (a :*: b) (c :*: d) = shallowEq p a c && shallowEq p b d + +instance SEq phi f => SEq phi (f :>: ix) where + shallowEq p (Tag a) (Tag b) = shallowEq p a b + +instance SEq phi f => SEq phi (C c f) where + shallowEq p (C a) (C b) = shallowEq p a b + +instance (Traversable t, Eq (t ()), SEq phi f) => SEq phi (t :.: f) where + shallowEq p (D a) (D b) = fmap (const ()) a == fmap (const ()) b + && and (zipWith (shallowEq p) (toList a) (toList b))
+ Generics/MultiRec/Transformations/Children.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverlappingInstances #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Generics.MultiRec.Transformations.Children where + +import Generics.MultiRec hiding ( show, foldM ) +import Data.Foldable ( toList ) + +import Generics.MultiRec.CountIs +import Generics.MultiRec.Transformations.Path + +-------------------------------------------------------------------------------- +-- Children +-------------------------------------------------------------------------------- + +-- | Get all children with their paths +allChildren :: forall phi ix xi. (Fam phi, Children phi (PF phi) xi) + => phi ix -> phi xi -> ix -> [(Path phi xi ix, xi)] +allChildren p1 p2 = map (\(p,x) -> (p, unI0 x)) . children f p1 p2 (\w z -> Push w z Empty) . from p1 where + f :: forall ix'. phi ix' -> phi xi -> (Path phi ix' ix) -> I0 ix' + -> [(Path phi xi ix, I0 xi)] + f p1' p2' w (I0 y) = map (\(w', x) -> (w <.> w', I0 x)) $ allChildren p1' p2' y + +class Children phi (f :: (* -> *) -> * -> *) xi where + children :: (forall ix'. phi ix' -> phi xi + -> Path phi ix' ix + -> r ix' -> [(Path phi xi ix,r xi)]) + -> phi ix -> phi xi -> (forall xi. phi xi -> Dir f xi ix -> Path phi xi ix) + -> f r ix -> [(Path phi xi ix, r xi)] + +instance (Fam phi, El phi ix) => Children phi (I ix) ix where + children f p1 p2 w (I r) = (w p2 CId, r) : f proof proof (w p2 CId) r + +instance (Fam phi, El phi ix, El phi xi) => Children phi (I xi) ix where + children f p1 p2 w (I r) = f proof proof (w proof CId) r + +instance Children phi (K a) ix where + children _ _ _ _ _ = [] + +instance Children phi U ix where + children _ _ _ _ _ = [] + +instance (Children phi f ix, Children phi g ix) => Children phi (f :+: g) ix where + children f p1 p2 w (L x) = children f p1 p2 (\w' -> w w' . CL) x + children f p1 p2 w (R x) = children f p1 p2 (\w' -> w w' . CR) x + +instance (Children phi f ix, Children phi g ix, CountIs g) + => Children phi (f :*: g) ix where + children f p1 p2 w (x :*: y) = children f p1 p2 (\w' z -> w w' (C1 z nullY)) x + ++ children f p1 p2 (\w' z -> w w' (C2 nullX z)) y + where nullX = error "nullX" -- fmap (const ()) x + nullY = error "nullY" -- fmap (const ()) y + +instance (Constructor c, Children phi f ix) => Children phi (C c f) ix where + children f p1 p2 w (C x) = children f p1 p2 (\w' -> w w' . CC) x + +instance Children phi f ix => Children phi (f :>: xi) ix where + children f p1 p2 w (Tag x) = children f p1 p2 (\w' -> w w' . CTag) x + +{- +instance (Traversable t, Children phi f ix) => Children phi (t :.: f) ix where + children f p1 p2 w (D x) = concatMap (\(i,x) -> children f p1 p2 (w . TrvI i) x) + $ zip [0..] (toList x) +-} + +instance (Children phi f ix) => Children phi (Maybe :.: f) ix where + children f p1 p2 w (D x) = concatMap (children f p1 p2 (\w' -> w w' . CCM)) . toList $ x + +instance (Children phi f ix) => Children phi ([] :.: f) ix where + children f p1 p2 w (D x) = concatMap (\(i,x) -> children f p1 p2 (\w' z -> w w' (CCL (ll i) z lr)) x) + $ zip [0..] x + where ll i = replicate i (error "oops4") + lr = error "oops5"
− Generics/MultiRec/Transformations/Explicit.hs
@@ -1,442 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ScopedTypeVariables #-}--module Generics.MultiRec.Transformations.Explicit (- diff, apply, Transformation, AnyInsert (..), WithRef (..), Path, - Transform, OrdI (..),- HasRef (..), NiceTransformation, NiceInsert (..),- toNiceTransformation, fromNiceTransformation- ) where--import Generics.MultiRec.Any-import Generics.MultiRec.Eq-import Generics.MultiRec.Ord--import Generics.MultiRec hiding (show, foldM)-import Control.Applicative ( (<|>) )-import Control.Monad (foldM)-import Control.Monad.State hiding (foldM)-import Data.Monoid (mappend)-import qualified Data.Map as Map-import Data.Map (Map)------------------------------------------------------------------------------------- Paths, annotations, edits and existentials----------------------------------------------------------------------------------data WithRef phi f a = InR (PF phi f a)- | Ref Path--type Path = [Int]--data AnyInsert phi where- AnyInsert :: phi ix -> Path -> HFix (WithRef phi) ix -> AnyInsert phi--type Transformation phi = [ AnyInsert phi]--class (Fam phi, Children phi (PF phi), CountI phi (PF phi),- HFunctor phi (PF phi), SEq phi (PF phi), ExtractN phi (PF phi), - MapN phi (PF phi), EqS phi, HEq phi (PF phi), HOrd phi (PF phi),- OrdI phi) => Transform phi------------------------------------------------------------------------------------- Applying------------------------------------------------------------------------------------ | Apply the transformation to the given tree-apply :: forall phi ix. (Transform phi)- => phi ix -> ix -> Transformation phi -> Maybe ix-apply p t = foldM (apply' p) t where- apply' :: forall ix. phi ix -> ix -> AnyInsert phi -> Maybe ix- apply' p' _ (AnyInsert p'' [] c) = case eqS p' p'' of - Just Refl -> lookupRefs p t p' c- Nothing -> Nothing- apply' p' a (AnyInsert p'' (i:is) c) =- liftM (to p') $ tmapN f p' $ from p' a where- f :: forall ix. Int -> phi ix -> I0 ix -> Maybe (I0 ix)- f j p''' x | i == j = liftM I0 (apply' p''' (unI0 x) (AnyInsert p'' is c))- | otherwise = return x---- | Look up the references using the original structure-lookupRefs :: forall phi ix ix'. (Fam phi, HFunctor phi (PF phi), ExtractN phi (PF phi), EqS phi) - => phi ix -> ix -> phi ix' -> HFix (WithRef phi) ix' -> Maybe ix'-lookupRefs p r p' = build . hout where- build :: WithRef phi (HFix (WithRef phi)) ix' -> Maybe ix'- build (InR x) = liftM (to p') (hmapM (\p'' -> liftM I0 . lookupRefs p r p'') p' x)- build (Ref l) = extract l p r >>= matchAny p'---- | Extract the subtree at the given path-extract :: (Fam phi, ExtractN phi (PF phi)) => Path -> phi ix -> ix -> Maybe (Any phi)-extract [] p a = return $ Any p a-extract (i:is) p a = extractN i p a >>= \(Any p' x) -> extract is p' x------------------------------------------------------------------------------------- Memoisation------------------------------------------------------------------------------------ | Comparing index of different types-class OrdI phi where- compareI :: phi ix -> phi ix' -> Ordering- compareI p1 p2 = compare (indexI p1) (indexI p2)- indexI :: phi ix -> Int- indexI = error "At least compareI or indexI should be implemented."---- | Key used in memoisation table-data MemoKey phi where- MemoKey :: phi ix -> Bool -> ix -> ix -> MemoKey phi--instance (EqS phi, Fam phi, HEq phi (PF phi)) => Eq (MemoKey phi) where- (MemoKey p1 a1 b1 c1) == (MemoKey p2 a2 b2 c2) = case eqS p1 p2 of- Nothing -> False- Just Refl -> a1 == a2 && eq p1 b1 b2 && eq p1 c1 c2--instance (EqS phi, Fam phi, OrdI phi, HEq phi (PF phi), HOrd phi (PF phi))- => Ord (MemoKey phi) where- compare (MemoKey p1 a1 b1 c1) (MemoKey p2 a2 b2 c2) = case eqS p1 p2 of- Nothing -> compareI p1 p2- Just Refl -> compare a1 a2 `mappend` gcompare p1 b1 b2 - `mappend` gcompare p1 c1 c2---- | The type of the memo table-type MemoTable phi = Map (MemoKey phi) (Transformation phi)-type Memo phi a = State (MemoTable phi) a--runMemo :: Memo phi a -> a-runMemo = flip evalState Map.empty--recMemo :: (Fam phi, HEq phi (PF phi), HOrd phi (PF phi), EqS phi, OrdI phi) => - (forall ix. Bool -> phi ix -> ix -> ix -> Memo phi (Transformation phi))- -> Bool -> phi ix -> ix -> ix -> Memo phi (Transformation phi)-recMemo f a p b c = do- mp <- get- let k = MemoKey p a b c- case Map.lookup k mp of- Just r -> return r- Nothing -> do- r <- f a p b c- modify (Map.insert k r)- return r------------------------------------------------------------------------------------- Diffing------------------------------------------------------------------------------------ | Find a set of insertions to transform the first into the second tree-diff :: forall phi ix. (Transform phi)- => phi ix -> ix -> ix -> Transformation phi-diff p a b = runMemo (build False p a b)- where- childPaths :: [(Any phi, Path)]- childPaths = childrenPaths p a- build :: forall ix. Bool -> phi ix -> ix -> ix -> Memo phi (Transformation phi)- build False p' a' b' | eq p' a' b' = return []- build ins p' a' b' = case anyLookup p' b' childPaths of- Just l -> return [ AnyInsert p' [] (HIn $ Ref l) ]- Nothing -> uses >>= maybe insert return -- Only insert when we cannot reuse- where- -- Construct the edits for the children based on a root- construct :: Bool -> ix -> Memo phi (Maybe (Transformation phi))- construct ins' c = - if shallowEq p' (from p' c) (from p' b')- then do r <- zipWithM (\(Any p1 c1) (Any p2 c2) -> case eqS p1 p2 of- Just Refl -> recMemo build ins' p1 c1 c2)- (imChildren p' c) (imChildren p' b')- return $ Just $ concat $ updateChildPaths r- else return Nothing- -- Possible edits reusing the existing tree or using a part of- -- the original tree. The existing tree is only used if we didn't- -- just insert it, since we want to keep the inserts small- uses :: Memo phi (Maybe (Transformation phi))- uses = reuses >>= \re -> case re of- Just r | ins -> return re- _ -> construct ins a' >>= return . pickBest re- -- Possible edits that include reusing a part of the original tree- reuses :: Memo phi (Maybe (Transformation phi))- reuses = foldM f Nothing childPaths where- addRef :: Path -> Maybe (Transformation phi) - -> Maybe (Transformation phi)- addRef l = liftM ((AnyInsert p' [] (HIn $ Ref l)):)- f c (Any p'' x, l) = case eqS p' p'' of- Just Refl -> construct False x >>= return . pickBest c . addRef l- Nothing -> return c- -- Best edit including insertion, only chosen if nothing can be reused- insert :: Memo phi (Transformation phi)- insert = do- Just r <- construct True b'- let (r',e') = partialApply p' (annotate p' b') r- return $ (AnyInsert p' [] r') : e'---- | Pick the best edit-pickBest :: Maybe (Transformation phi) -> Maybe (Transformation phi) -> Maybe (Transformation phi)-pickBest e1 e2 = case (e1,e2) of- (Just e1', Just e2') -> Just (pickShortest e1' e2')- _ -> e1 <|> e2---- | Pick the shortest of two lists lazily-pickShortest :: [a] -> [a] -> [a]-pickShortest a b = if f a b then a else b- where f [] _ = True- f _ [] = False- f (_:xs) (_:ys) = f xs ys---- | Lookup with a specific type-anyLookup :: (Fam phi, EqS phi, HEq phi (PF phi))- => phi ix -> ix -> [(Any phi, a)] -> Maybe a-anyLookup p _ [] = Nothing-anyLookup p x ((Any p' y,r) : ys) = case eqS p p' of- Just Refl | eq p x y -> Just r- _ -> anyLookup p x ys---- | Lift a tree to an edit structure-annotate :: (Fam phi, HFunctor phi (PF phi)) => phi ix -> ix -> HFix (WithRef phi) ix-annotate p = HIn . InR . hmap (\p' (I0 x) -> annotate p' x) p . from p---- | Extend the paths of edits for the children with the child number-updateChildPaths :: [Transformation phi] -> [Transformation phi]-updateChildPaths = zipWith (\n -> map (\(AnyInsert p l c) -> (AnyInsert p (n:l) c))) [0..]---- | Try to apply as much edits to the edit structure as possible--- to make the final edit smaller-partialApply :: (Fam phi, CountI phi (PF phi), ExtractN phi (PF phi), MapN phi (PF phi), EqS phi)- => phi ix -> HFix (WithRef phi) ix -> Transformation phi -> (HFix (WithRef phi) ix, Transformation phi)-partialApply _ a [] = (a, [])-partialApply p a (AnyInsert p' l x : xs) = case replace p' l x p a of- Just a' -> partialApply p a' xs- Nothing -> let (a',xs') = partialApply p a xs in (a', AnyInsert p' l x : xs')---- | Replace a subtree in an edit structure-replace :: forall phi ix ix'. (Fam phi, EqS phi, MapN phi (PF phi))- => phi ix -> Path -> HFix (WithRef phi) ix- -> phi ix' -> HFix (WithRef phi) ix' -> Maybe (HFix (WithRef phi) ix')-replace p [] r p' _ = case eqS p p' of- Just Refl -> Just r- Nothing -> Nothing-replace p (i:is) r p' a = case hout a of- Ref _ -> Nothing- InR a' -> liftM HIn . liftM InR . tmapN f p' $ a'- where f :: forall ix. Int -> phi ix -> HFix (WithRef phi) ix -> Maybe (HFix (WithRef phi) ix)- f j p'' = if i == j then replace p is r p'' else Just------------------------------------------------------------------------------------- Shallow equality-----------------------------------------------------------------------------------class SEq phi (f :: (* -> *) -> * -> *) where- shallowEq :: phi ix -> f r ix -> f r ix -> Bool--instance El phi xi => SEq phi (I xi) where- shallowEq _ (I _) (I _) = True--instance SEq phi U where- shallowEq _ U U = True--instance Eq a => SEq phi (K a) where- shallowEq p (K a) (K b) = a == b--instance (SEq phi f, SEq phi g) => SEq phi (f :+: g) where- shallowEq p (L a) (L b) = shallowEq p a b- shallowEq p (R a) (R b) = shallowEq p a b- shallowEq _ _ _ = False--instance (SEq phi f, SEq phi g) => SEq phi (f :*: g) where- shallowEq p (a :*: b) (c :*: d) = shallowEq p a c && shallowEq p b d--instance SEq phi f => SEq phi (f :>: ix) where- shallowEq p (Tag a) (Tag b) = shallowEq p a b--instance SEq phi f => SEq phi (C c f) where- shallowEq p (C a) (C b) = shallowEq p a b---- Todo: is this the best choice?-instance SEq phi ([] :.: ix) where- shallowEq p (D a) (D b) = length a == length b------------------------------------------------------------------------------------- ExtractN-----------------------------------------------------------------------------------extractN :: (Fam phi, ExtractN phi (PF phi), Monad m) - => Int -> phi ix -> ix -> m (Any phi)-extractN i p v = extractN' (\p (I0 v) -> Any p v) i p (from p v)--class ExtractN phi (f :: (* -> *) -> * -> *) where- extractN' :: Monad m => (forall ix. phi ix -> r ix -> r')- -> Int -> phi ix -> f r ix -> m r'--instance El phi xi => ExtractN phi (I xi) where- extractN' mka 0 _ (I r) = return $ mka proof r- extractN' _ _ _ (I _) = fail "extractN"--instance ExtractN phi (K a) where- extractN' mka _ _ (K _) = fail "extractN"--instance ExtractN phi U where- extractN' mka _ _ U = fail "extractN"--instance (ExtractN phi f, ExtractN phi g) => ExtractN phi (f :+: g) where- extractN' mka i p (L x) = extractN' mka i p x- extractN' mka i p (R x) = extractN' mka i p x--instance (CountI phi f, ExtractN phi f, ExtractN phi g) => ExtractN phi (f :*: g) where- extractN' mka i p (x :*: y) = let n = countI p x- in if i < n then extractN' mka i p x- else extractN' mka (i-n) p y--instance ExtractN phi f => ExtractN phi (f :>: ix) where- extractN' mka i p (Tag x) = extractN' mka i p x--instance ExtractN phi f => ExtractN phi (C c f) where- extractN' mka i p (C x) = extractN' mka i p x---- Todo: is this the best choice?-instance ExtractN phi f => ExtractN phi ([] :.: f) where- extractN' mka i p (D x) = extractN' mka 0 p (x !! i)------------------------------------------------------------------------------------- MapN------------------------------------------------------------------------------------- | Map a function with child index at a top-level structure-tmapN :: (Fam phi, MapN phi f, Monad m)- => (forall ix. Int -> phi ix -> r ix -> m (r' ix))- -> phi ix -> f r ix -> m (f r' ix)-tmapN = mapN 0--class MapN phi (f :: (* -> *) -> * -> *) where- mapN :: Monad m => Int -> (forall ix. Int -> phi ix -> r ix -> m (r' ix))- -> phi ix -> f r ix -> m (f r' ix)--instance El phi xi => MapN phi (I xi) where- mapN i f p (I x) = liftM I (f i proof x)--instance MapN phi (K a) where- mapN _ _ _ (K x) = return $ K x--instance MapN phi U where- mapN _ _ _ U = return U--instance (MapN phi f, MapN phi g) => MapN phi (f :+: g) where- mapN i f p (L x) = liftM L (mapN i f p x)- mapN i f p (R x) = liftM R (mapN i f p x)---- Here we increment our parameter. Does not require right-nested products-instance (CountI phi f, MapN phi f, MapN phi g) => MapN phi (f :*: g) where- mapN i f p (x :*: y) = liftM2 (:*:) (mapN i f p x) (mapN (i + countI p x) f p y)--instance MapN phi f => MapN phi (f :>: ix) where- mapN i f p (Tag x) = liftM Tag (mapN i f p x)--instance MapN phi f => MapN phi (C c f) where- mapN i f p (C x) = liftM C (mapN i f p x)---- Todo: is this the best choice?-instance (CountI phi f, MapN phi f) => MapN phi ([] :.: f) where- mapN i f p (D []) = return $ D []- mapN i f p (D (x:xs)) = do h <- mapN i f p x- t <- mapN (i + countI p x) f p (D xs)- return $ D (h : unD t)------------------------------------------------------------------------------------- CountI-----------------------------------------------------------------------------------class CountI phi (f :: (* -> *) -> * -> *) where- -- | Count the number of recursive occurrences- countI :: phi ix -> f r ix -> Int--instance El phi xi => CountI phi (I xi) where- countI _ _ = 1--instance CountI phi (K a) where- countI _ _ = 0--instance CountI phi U where- countI _ _ = 0--instance (CountI phi f, CountI phi g) => CountI phi (f :+: g) where- countI p (L x) = countI p x- countI p (R x) = countI p x--instance (CountI phi f, CountI phi g) => CountI phi (f :*: g) where- countI p (x :*: y) = countI p x + countI p y--instance CountI phi f => CountI phi (f :>: ix) where- countI p (Tag x) = countI p x--instance CountI phi f => CountI phi (C c f) where- countI p (C x) = countI p x---- Todo: is this the best choice?-instance CountI phi f => CountI phi ([] :.: f) where- countI p (D x) = sum (map (countI p) x)------------------------------------------------------------------------------------- Children------------------------------------------------------------------------------------- | Get the immediate children-imChildren :: (Fam phi, Children phi (PF phi)) => phi ix -> ix -> [Any phi]-imChildren p x = children (\p (I0 v) -> Any p v) p (from p x)---- | Get all children with their paths-childrenPaths :: (Fam phi, Children phi (PF phi)) => phi ix -> ix -> [(Any phi, Path)]-childrenPaths p a = (Any p a, []) : - [ (r, n : p)- | (n, Any p' c) <- zip [0..] (imChildren p a)- , (r, p) <- childrenPaths p' c ]--class Children phi (f :: (* -> *) -> * -> *) where- children :: (forall ix. phi ix -> r ix -> Any phi) -> phi ix -> f r ix -> [Any phi]--instance (Fam phi, El phi xi) => Children phi (I xi) where- children mka _ (I r) = [mka proof r]--instance Children phi (K a) where- children _ _ (K _) = []--instance Children phi U where- children _ _ U = []--instance (Children phi f, Children phi g) => Children phi (f :+: g) where- children mka p (L x) = children mka p x- children mka p (R x) = children mka p x--instance (Children phi f, Children phi g) => Children phi (f :*: g) where- children mka p (x :*: y) = children mka p x ++ children mka p y--instance Children phi f => Children phi (C c f) where- children mka p (C x) = children mka p x--instance Children phi f => Children phi (f :>: ix) where- children mka p (Tag x) = children mka p x---- Todo: is this the best choice?-instance Children phi f => Children phi ([] :.: f) where- children mka p (D x) = concatMap (children mka p) x------------------------------------------------------------------------------------- Nicer interface-----------------------------------------------------------------------------------class HasRef phi where- type RefRep phi ix- -- I don't like HFix here but can't figure out how to do a- -- single step unwrapping- toRef :: phi ix -> HFix (WithRef phi) ix -> RefRep phi ix- fromRef :: phi ix -> RefRep phi ix -> HFix (WithRef phi) ix--data NiceInsert phi where- NiceInsert :: phi ix -> Path -> RefRep phi ix -> NiceInsert phi--type NiceTransformation phi = [ NiceInsert phi]--toNiceTransformation :: HasRef phi => Transformation phi -> NiceTransformation phi-toNiceTransformation = map f- where f (AnyInsert p l x) = NiceInsert p l (toRef p x)--fromNiceTransformation :: HasRef phi => NiceTransformation phi -> Transformation phi-fromNiceTransformation = map f- where f (NiceInsert p l x) = AnyInsert p l (fromRef p x)
+ Generics/MultiRec/Transformations/Main.hs view
@@ -0,0 +1,190 @@+{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE ConstraintKinds #-} + +module Generics.MultiRec.Transformations.Main + ( diff, apply, Ixs, Transformation ) + where + +import Generics.MultiRec hiding ( show, foldM ) +import Control.Applicative ( (<|>) ) +import Control.Monad ( foldM ) +import Control.Monad.State hiding ( foldM, mapM ) + +import Generics.MultiRec.ShallowEq +import Generics.MultiRec.Transformations.Path +import Generics.MultiRec.Transformations.Children +import Generics.MultiRec.Transformations.ZipChildren +import Generics.MultiRec.Transformations.MemoTable + +-------------------------------------------------------------------------------- +-- Synonyms +-------------------------------------------------------------------------------- + +-- | A constraint synonym for convenience +type Transform phi = ( Fam phi, HFunctor phi (PF phi), SEq phi (PF phi) + , ZipChildren phi (PF phi), MapP phi (PF phi) + , Extract (PF phi)) + +-- | Transformations are just sequences of insertions +type Transformation phi top = [ Insert phi top top ] + +-------------------------------------------------------------------------------- +-- Applying +-------------------------------------------------------------------------------- + +-- | Apply the transformation to the given tree +apply :: forall phi ix. (Transform phi) + => phi ix -> ix -> Transformation phi ix -> Maybe ix +apply p t = foldM apply' t where + apply' :: ix -> Insert phi ix ix -> Maybe ix + apply' a (Insert _ loc repl) = mapP p loc (\pt _ -> lookupRefs p t pt repl) a + +-- | Look up the references using the original structure +lookupRefs :: forall phi top a. (Transform phi) + => phi top -> top -> phi a -> HWithRef phi top a -> Maybe a +lookupRefs p r p' (HIn (InR x)) = liftM (to p') $ + hmapM (\p'' -> liftM I0 . lookupRefs p r p'') p' x +lookupRefs p r _ (HIn (Ref loc)) = extract p loc r + +-- | Extract the subtree at the given path +extract :: forall phi i t. (Transform phi) + => phi i -> Path phi t i -> i -> Maybe t +extract w1 Empty x = Just x +extract w1 (Push w2 p ps) x = fmap unI0 (extract' return w1 p (from w1 x)) + >>= extract w2 ps + +class Extract f where + extract' :: (r t -> Maybe (r t)) + -> phi ix -> Dir f t ix -> f r ix -> Maybe (r t) + +instance (Extract f, Extract g) => Extract (f :+: g) where + extract' f w (CL p) (L x) = extract' f w p x + extract' f w (CR p) (R x) = extract' f w p x + extract' f w _ _ = Nothing + +instance (Extract f, Extract g) => Extract (f :*: g) where + extract' f w (C1 p _) (x :*: _) = extract' f w p x + extract' f w (C2 _ p) (_ :*: y) = extract' f w p y + +instance Extract (I ix) where + extract' f w CId (I x) = f x + +instance Extract U where extract' _ _ _ _ = Nothing +instance Extract (K a) where extract' _ _ _ _ = Nothing + +instance (Extract f) => Extract (f :>: ix) where + extract' f w (CTag p) (Tag x) = extract' f w p x + +instance (Extract f) => Extract (C c f) where + extract' f w (CC p) (C x) = extract' f w p x + +instance (Extract f) => Extract (Maybe :.: f) where + extract' f w (CCM p) (D x) = x >>= extract' f w p + +instance (Extract f) => Extract ([] :.: f) where + extract' f w (CCL l p _) (D x) = extract' f w p (x !! length l) + +-------------------------------------------------------------------------------- +-- Diffing +-------------------------------------------------------------------------------- +-- | Find a set of insertions to transform the first into the second tree + +-- Jeroen says: we could make the code of uses nicer if we define a +-- <|>' :: Monad m => m (Maybe a) -> m (Maybe a) -> m (Maybe a) +-- then it will look similar to the version in the paper +diff :: forall phi top. (Transform phi, Children phi (PF phi) top, EmptyMemo phi top (Ixs phi), ChildrenTable phi top (Ixs phi), GetChildrenTable phi (Ixs phi) top, Eq top) + => phi top -> top -> top -> Transformation phi top +diff p a b = runMemo (Proxy :: Proxy '(phi,top)) $ build False p a b where + chTbl :: HList (ChildTable phi top (Ixs phi)) + chTbl = childrenTable (Proxy :: Proxy '(phi, top,Ixs phi)) a + build :: forall a. (Children phi (PF phi) a, Eq a, GetChildrenTable phi (Ixs phi) a) => Bool -> phi a -> a -> a -> Memo phi top [ Insert phi top a ] + build False p' a' b' | a' == b' = return [] + build ins p' a' b' = + let -- All children of this type + allChildren :: Children phi (PF phi) a => [(Path phi a top, a)] + allChildren = getChTable (Proxy :: Proxy '(phi, top, Ixs phi)) chTbl + in case childLookup p' b' allChildren of + Just l -> return [ Insert p' Empty (HIn (Ref l)) ] + Nothing -> uses >>= maybe insert return where -- Only insert when we cannot reuse + -- Construct the edits for the children based on a root + construct :: Bool -> a -> Memo phi top (Maybe [ Insert phi top a ]) + construct ins' c = + if shallowEq p' (from p' c) (from p' b') + then do r <- zipChildrenM p' + (\p1 l1 c1 c2 -> recMemo build ins' p1 c1 c2 + >>= return . map (updatePath l1) + ) c b' + return $ Just $ concat r + else return Nothing + -- Possible edits reusing the existing tree or using a part of + -- the original tree. The existing tree is only used if we didn't + -- just insert it, since we want to keep the inserts small + uses :: Memo phi top (Maybe [ Insert phi top a ]) + uses = reuses >>= \re -> case re of + Just r | ins -> return re + _ -> construct ins a' >>= return . pickBest re + -- Possible edits that include reusing a part of the original tree + reuses :: Memo phi top (Maybe [ Insert phi top a ]) + reuses = foldM f Nothing allChildren where + f :: Maybe [ Insert phi top a ] -> (Path phi a top, a) + -> Memo phi top (Maybe [ Insert phi top a ]) + f c (l,x) = construct False x >>= return . pickBest c . addRef l + addRef :: Path phi a top -> Maybe [ Insert phi top a ] + -> Maybe [ Insert phi top a ] + addRef l = liftM ((Insert p' Empty (HIn (Ref l))):) + -- Best edit including insertion, only chosen if nothing can be reused + insert :: Memo phi top [ Insert phi top a ] + insert = do + Just r <- construct True b' + let (r',e') = partialApply p' (annotate p' b') r + return $ (Insert p' Empty r') : e' + +-- | Update insert location +updatePath :: Path phi a b -> Insert phi top a -> Insert phi top b +updatePath p (Insert w loc v) = Insert w (p <.> loc) v + +-- | Pick the best edit +pickBest :: Maybe [a] -> Maybe [a] -> Maybe [a] +pickBest e1 e2 = case (e1,e2) of + (Just e1', Just e2') -> Just (pickShortest e1' e2') + _ -> e1 <|> e2 + +-- | Pick the shortest of two lists lazily +pickShortest :: [a] -> [a] -> [a] +pickShortest a b = if f a b then a else b + where f [] _ = True + f _ [] = False + f (_:xs) (_:ys) = f xs ys + +-- | Lookup a child with a given type +childLookup :: (Fam phi, Eq t) + => phi t -> t -> [(Path phi t ix, t)] -> Maybe (Path phi t ix) +childLookup p _ [] = Nothing +childLookup p x ((r,y) : ys) | x == y = Just r + | otherwise = childLookup p x ys + +-- | Lift a tree to an edit structure +annotate :: (Fam phi, HFunctor phi (PF phi)) + => phi ix -> ix -> HWithRef phi top ix +annotate p = HIn . InR . hmap (\p' (I0 x) -> annotate p' x) p . from p + +-- | Try to apply as much edits to the edit structure as possible +-- to make the final edit smaller +partialApply :: forall phi top a. (Transform phi) + => phi a + -> HWithRef phi top a + -> [Insert phi top a] + -> (HWithRef phi top a, [Insert phi top a]) +partialApply _ a [] = (a, []) +partialApply p a (Insert w l x : xs) = case mapPR p l (\_ _ -> Just x) a of + Just a' -> partialApply p a' xs + Nothing -> let (a',xs') = partialApply p a xs in (a', Insert w l x : xs')
+ Generics/MultiRec/Transformations/MemoTable.hs view
@@ -0,0 +1,165 @@+{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE OverlappingInstances #-} +{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE PolyKinds #-} + +module Generics.MultiRec.Transformations.MemoTable where + +import Generics.MultiRec hiding ( show, foldM ) +import Control.Monad.State hiding ( foldM, mapM ) +import qualified Data.Map as Map +import Data.Map ( Map ) + +import Generics.MultiRec.Transformations.Path +import Generics.MultiRec.Transformations.Children + +-------------------------------------------------------------------------------- +-- One memotable per type in the family +-------------------------------------------------------------------------------- +type family Ixs (phi :: * -> *) :: [*] -- one instance per family; tells us + -- which types are in the family + +data HList (l :: [*]) where -- heterogeneous collections + HNil :: HList '[] + HCons :: h -> HList t -> HList (h ': t) + +type family HMap (h :: * -> * -> *) (f :: * -> *) (g :: * -> *) (l :: [*]) :: [*] +type instance HMap h f g '[] = '[] +type instance HMap h f g (t ': ts) = h (f t) (g t) ': HMap h f g ts + +-- Memotables are now heterogenous collections mapping keys to values, indexed +-- over each family type +-- type MemoTable' phi top ixs = HList (HMap Map (MemKey' top) (MemVal' top) ixs) +type MemoTable phi top ixs = HList (MemoTable' One phi top ixs) + +data Type = One | Two + +type family MemoTable' (x :: Type) (phi :: * -> *) top (ixs :: [*]) :: [*] +type instance MemoTable' x phi top '[] = '[] +type instance MemoTable' x phi top (t ': ts) = MemCell x phi top t + ': MemoTable' x phi top ts + +type family MemCell (x :: Type) (phi :: * -> *) top (t :: *) :: * +-- type instance MemCell One phi top t = Map (MemKey t) (MemVal phi top t) +type instance MemCell One phi top t = Map (MemKey t) (MemVal phi top t) + +type MemKey t = (Bool, t, t) +type MemVal phi top t = [Insert phi top t] + +-- Lookup on the right table +data Proxy (t :: k) = Proxy +class {- (ixs ~ Ixs phi) => -} Lookup phi (ixs :: [*]) ix where + lookupMT :: Proxy '(phi, ixs) + -- I don't like this Proxy too much, but I'm afraid it's necessary + -> MemoTable phi top ixs -> MemKey ix -> Maybe (MemVal phi top ix) + insertMT :: Proxy '(phi, ixs) + -> MemKey ix -> MemVal phi top ix + -> MemoTable phi top ixs -> MemoTable phi top ixs + +-- this probably shouldn't happen... +instance Lookup phi '[] ix where + lookupMT _ HNil _ = Nothing + insertMT _ _ _ HNil = HNil + +-- this is the right memotable for this type +instance (Ord t) => Lookup phi (t ': ts) t where + lookupMT _ (HCons mt _) k = Map.lookup k mt + insertMT _ k v (HCons mt tl) = HCons (Map.insert k v mt) tl + +-- this is not the right memotable for this type, keep searching +instance (Lookup phi ts ix) => Lookup phi (t ': ts) ix where + lookupMT _ (HCons _ mts) = lookupMT (Proxy :: Proxy '(phi, ts)) mts + insertMT _ k v (HCons hd mts) = HCons hd (insertMT (Proxy :: Proxy '(phi, ts)) k v mts) + +type Memo phi top a = State (MemoTable phi top (Ixs phi)) a + +class EmptyMemo (phi :: * -> *) top (ixs :: [*]) where + emptyMemo :: Proxy '(phi,top,ixs) -> MemoTable phi top ixs + +instance EmptyMemo phi top '[] where + emptyMemo _ = HNil + +instance (EmptyMemo phi top t) => EmptyMemo phi top (h ': t) where + emptyMemo _ = HCons Map.empty (emptyMemo (Proxy :: Proxy '(phi,top,t))) + +runMemo :: forall phi top a. (EmptyMemo phi top (Ixs phi)) + => Proxy '(phi,top) -> Memo phi top a -> a +runMemo _ = flip evalState (emptyMemo (Proxy :: Proxy '(phi,top,Ixs phi))) + +recMemo :: forall phi top ix. + (Fam phi, Children phi (PF phi) ix, Lookup phi (Ixs phi) ix, Eq ix, GetChildrenTable phi (Ixs phi) ix) => + (forall ix. (Children phi (PF phi) ix, Lookup phi (Ixs phi) ix, Eq ix, GetChildrenTable phi (Ixs phi) ix) => Bool -> phi ix -> ix -> ix -> Memo phi top [ Insert phi top ix ]) + -> Bool -> phi ix -> ix -> ix -> Memo phi top [ Insert phi top ix ] +recMemo f a p b c = do + mp <- get + let k = (a,b,c) + case lookupMT (Proxy :: Proxy '(phi, Ixs phi)) mp k of + Just r -> return r + Nothing -> do + r <- f a p b c + modify $ insertMT (Proxy :: Proxy '(phi, Ixs phi)) k r + return r + +-------------------------------------------------------------------------------- +-- Memo table of all children +-------------------------------------------------------------------------------- +-- type family ChildTable (phi :: * -> *) top (ixs :: [*]) :: [*] +-- type instance ChildTable phi top '[] = '[] +-- type instance ChildTable phi top (t ': ts) = [(Path phi top t, t)] ': ChildTable phi top ts + +type ChildTable phi top ixs = MemoTable' Two phi top ixs +type instance MemCell Two phi top t = [(Path phi t top, t)] + +{- +This is a first step to merge ChildTable and MemoTable. However, it would be +really cool if we can also merge getChTable and lookupMT, for example. But for +that we have to change MemCell to either be a Map or a list of pairs. + +Changing ChildTable to use a Map as its cell isn't nice, because we start +requiring |Ord (r ix)| constraints in AllChildren. + +The other way around, changing MemoTable to use a list of pairs instead, is +probably possible, but I'm not sure if it's a good idea. I'd like Jeroen's +opinion on this. +-} + +class ChildrenTable (phi :: * -> *) top (ixs :: [*]) where + childrenTable :: Proxy '(phi,top,ixs) -> top -> HList (ChildTable phi top ixs) + +instance ChildrenTable phi top '[] where + childrenTable _ _ = HNil + +-- For the toplevel type, also include full tree +instance (Fam phi, El phi top, Children phi (PF phi) top, ChildrenTable phi top t) + => ChildrenTable phi top (top ': t) where + childrenTable _ top = HCons ((Empty,top) : allChildren proof proof top) + (childrenTable (Proxy :: Proxy '(phi,top,t)) top) + +-- For all other types +instance (Fam phi, El phi h, El phi top, Children phi (PF phi) h, ChildrenTable phi top t) + => ChildrenTable phi top (h ': t) where + childrenTable _ top = HCons (allChildren proof proof top) + (childrenTable (Proxy :: Proxy '(phi,top,t)) top) + +class GetChildrenTable phi (ixs :: [*]) ix where + getChTable :: Proxy '(phi, top, ixs) + -- I don't like this Proxy too much, but I'm afraid it's necessary + -> HList (ChildTable phi top ixs) -> MemCell Two phi top ix + +instance GetChildrenTable phi '[] ix where + getChTable _ HNil = error "This shouldn't happen" + +instance (Ord t) => GetChildrenTable phi (t ': ts) t where + getChTable _ (HCons mt _) = mt + +-- this is not the right memotable for this type, keep searching +instance (GetChildrenTable phi ts ix) => GetChildrenTable phi (t ': ts) ix where + getChTable _ (HCons _ mts) = getChTable (Proxy :: Proxy '(phi, top, ts)) mts
+ Generics/MultiRec/Transformations/Path.hs view
@@ -0,0 +1,250 @@+{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} + +module Generics.MultiRec.Transformations.Path ( + module Generics.MultiRec.Transformations.Path + , Ctxs(..), Ctx(..) + ) where + +import Prelude as P hiding ( mapM, sequence ) +import Generics.MultiRec hiding ( show, foldM ) +import Generics.MultiRec.Zipper ( Ctxs(..), Ctx(..) ) +import Control.Monad.State hiding ( foldM, mapM, sequence ) +import Data.Traversable ( Traversable, mapM, sequence ) + +import Generics.MultiRec.CountIs + +-------------------------------------------------------------------------------- +-- Paths, annotations and edits +-------------------------------------------------------------------------------- +-- | A path is a list of connecting directions on a datatype. This is equivalent +-- to a zipper context where the recursive positions are ignored (set to a +-- constant type). +type Path phi t i = Ctxs phi t (K0 ()) i + +-- | A direction points to a single recursive position in a datatype. +type Dir f t i = Ctx f t (K0 ()) i + +-- | The type of pattern functors extended with references +data WithRef phi top r a = InR { unInR :: PF phi r a } + | Ref { unRef :: Path phi a top } + +-- | Closed functors extended with references +type HWithRef phi top t = HFix (WithRef phi top) t + +-- | Insertions contain a path of where to insert, and what to insert +data Insert phi top ix where + Insert :: phi t -> Path phi t ix -> HWithRef phi top t -> Insert phi top ix + +-------------------------------------------------------------------------------- +-- Path helpers +-------------------------------------------------------------------------------- + +-- | Concatenate two paths +(<.>) :: forall phi a b c. Path phi b a -> Path phi c b -> Path phi c a +Empty <.> p2 = p2 +(Push p x xs) <.> p2 = Push p x (xs <.> p2) +-------------------------------------------------------------------------------- +-- Show instances +-------------------------------------------------------------------------------- + +newtype ConIndex = CI Int deriving (Eq, Num) + +instance Show ConIndex where + show (CI (-1)) = "" + show (CI n ) = "_" ++ show n ++ " " + +class ShowPath f where + showsPrecPath :: ShowS -> ConIndex -> Int -> Dir f i t -> ShowS + +instance (ShowPath f, ShowPath g) => ShowPath (f :+: g) where + showsPrecPath r d n (CL p) = showsPrecPath r d n p + showsPrecPath r d n (CR p) = showsPrecPath r d n p + +instance (ShowPath f, ShowPath g, CountIs f) => ShowPath (f :*: g) where + -- Going left on a product is unproblematic + showsPrecPath r d n (C1 p _) = showsPrecPath r d n p + -- Going right, however, we have to increase |d| by the number of children to + -- our left, unless |d == -1|, which means we are under a composition, and + -- shouldn't print any indices anymore. + showsPrecPath r d n (C2 _ p) = + let newd = if d == -1 then -1 else d + CI (countIs (undefined :: f r ix)) + in showsPrecPath r newd n p + +instance (ShowPath f) => ShowPath (f :>: ix) where + showsPrecPath r d n (CTag p) = showsPrecPath r d n p + +instance (ShowPath f, Constructor c) => ShowPath (C c f) where + showsPrecPath r d n (CC p) = let name = conName (undefined :: C c f r ix) + in showParen (n > 10) $ showString name + . showsPrecPath r 0 11 p + +instance ShowPath (K a) where showsPrecPath _ _ _ _ = id +instance ShowPath U where showsPrecPath _ _ _ _ = id + +instance ShowPath (I ix) where + showsPrecPath r d n CId = shows d . r + +instance (ShowPath f) => ShowPath (Maybe :.: f) where + showsPrecPath r d n (CCM p) = shows d + . showParen (n > 10) + ( showString "Maybe_0 " + . showsPrecPath r (-1) 11 p) + +instance (ShowPath f) => ShowPath ([] :.: f) where + showsPrecPath r d n (CCL l1 p l2) = shows d + . showParen (n > 10) + ( showString "List_" + . P.showsPrec 11 (length l1) + . showChar ' ' + . showsPrecPath r (-1) 11 p) + +showsPrecPathC :: (ShowPath (PF phi)) + => ConIndex -> Int -> Path phi t i -> ShowS +showsPrecPathC d n Empty = showString "End" +showsPrecPathC d n (Push w p ps) = showsPrecPath (showsPrecPathC d n ps) d n p + +instance (ShowPath (PF phi)) => Show (Path phi t i) where + showsPrec = showsPrecPathC 0 + +instance (HFunctor phi (PF phi), HShow phi (PF phi), El phi ix, ShowPath (PF phi)) + => Show (HWithRef phi top ix) where + showsPrec = showWR proof + +instance (HFunctor phi (PF phi), HShow phi (PF phi), El phi ix, ShowPath (PF phi)) + => Show (Insert phi top ix) where + showsPrec n (Insert w p r) = showParen (n > 10) $ + showString "Insert " . spaces [P.showsPrec 11 p, showWR w 11 r] + +-- showsPrec for WithRef working with type index +showWR :: forall phi top ix. + (HFunctor phi (PF phi), HShow phi (PF phi), ShowPath (PF phi)) + => phi ix -> Int -> HWithRef phi top ix -> ShowS +showWR w n (HIn (InR p)) = showParen (n > 10) $ spaces (("InR"++) : map ($ 11) x) where + f :: forall ix. phi ix -> HWithRef phi top ix -> K0 [Int -> ShowS] ix + f w wr = K0 [\n -> showWR w n wr] + r :: PF phi (K0 [Int -> ShowS]) ix + r = hmap f w p + x :: [Int -> ShowS] + x = hShowsPrecAlg w r +showWR w n (HIn (Ref p)) = showParen (n > 10) $ showString "Ref " . P.showsPrec 11 p + +{- +showsPrecPath :: forall phi f i t. ConIndex -> Int -> Dir phi f i t -> ShowS +showsPrecPath d _ End = showString "End" +showsPrecPath d n (PlusL p) = showsPrecPath d n p +showsPrecPath d n (PlusR p) = showsPrecPath d n p + +-- Going left on a product is unproblematic +showsPrecPath d n (ProdL p) = showsPrecPath d n p + +-- Going right, however, we have to increase |d| by the number of children to +-- our left, unless |d == -1|, which means we are under a composition, and +-- shouldn't print any indices anymore. +showsPrecPath d n (ProdR (p :: Dir phi g i t)) = + let newd = if d == -1 then -1 else d + CI (countIs (undefined :: g r ix)) + in showsPrecPath newd n p + +showsPrecPath d n (TagP p) = showsPrecPath d n p +showsPrecPath d n (ConsP p) = let name = conName (undefined :: f r i) + in showParen (n > 10) $ showString name + . showsPrecPath 0 11 p +showsPrecPath d n (RecP _ p) = shows d . showsPrecPath d n p +showsPrecPath d n (TrvI i p) = shows d + . showParen (n > 10) (spaces + [ showString "TrvI" + , P.showsPrec 11 i + , showsPrecPath (-1) 11 p]) + +instance Show (Dir phi f i t) where + showsPrec = showsPrecPath 0 + +instance (HFunctor phi (PF phi), HShow phi (PF phi), El phi ix) + => Show (WithRef phi top ix) where + showsPrec = showWR proof + +instance (HFunctor phi (PF phi), HShow phi (PF phi), El phi ix) + => Show (Insert phi top ix) where + showsPrec n (Insert w p r) = showParen (n > 10) $ + showString "Insert " . spaces [P.showsPrec 11 p, showWR w 11 r] + +-- showsPrec for WithRef working with type index +showWR :: forall phi top ix. (HFunctor phi (PF phi), HShow phi (PF phi)) + => phi ix -> Int -> WithRef phi top ix -> ShowS +showWR w n (InR p) = showParen (n > 10) $ spaces (("InR"++) : map ($ 11) x) where + f :: forall ix. phi ix -> WithRef phi top ix -> K0 [Int -> ShowS] ix + f w wr = K0 [\n -> showWR w n wr] + r :: PF phi (K0 [Int -> ShowS]) ix + r = hmap f w p + x :: [Int -> ShowS] + x = hShowsPrecAlg w r +showWR w n (Ref p) = showParen (n > 10) $ showString "Ref " . P.showsPrec 11 p +-} + +-------------------------------------------------------------------------------- +-- MapP +-------------------------------------------------------------------------------- +mapP :: forall m phi i t. (Monad m, Fam phi, MapP phi (PF phi)) + => phi i -> Path phi t i -> (phi t -> t -> m t) -> i -> m i +mapP w1 Empty f = f w1 +mapP w1 (Push w2 y p) f = + liftM (to w1) . mapP' (\w -> liftM I0 . mapP w p f . unI0) w1 y . from w1 + +class MapP phi f where + mapP' :: Monad m + => (phi t -> r t -> m (r t)) + -> phi ix -> Dir f t ix -> f r ix -> m (f r ix) + +instance MapP phi U where mapP' f phi p = return +instance MapP phi (K a) where mapP' f phi p = return + +instance (El phi ix) => MapP phi (I ix) where + mapP' f phi CId (I x) = liftM I (f proof x) + +instance (MapP phi f, MapP phi g) => MapP phi (f :+: g) where + mapP' f phi (CL p) (L x) = liftM L (mapP' f phi p x) + mapP' f phi (CR p) (R x) = liftM R (mapP' f phi p x) + mapP' _ _ _ _ = fail "mapP': inconsistent sum" + +instance (MapP phi f, MapP phi g) => MapP phi (f :*: g) where + mapP' f phi (C1 p _) (x :*: y) = liftM2 (:*:) (mapP' f phi p x) (return y) + mapP' f phi (C2 _ p) (x :*: y) = liftM2 (:*:) (return x) (mapP' f phi p y) + +instance (MapP phi f) => MapP phi (C c f) where + mapP' f phi (CC p) (C x) = liftM C (mapP' f phi p x) + +instance (MapP phi f) => MapP phi (f :>: ix) where + mapP' f phi (CTag p) (Tag x) = liftM Tag (mapP' f phi p x) + +instance (MapP phi f) => MapP phi (Maybe :.: f) where + mapP' f phi (CCM p) = liftM D . sequence . liftM (mapP' f phi p) . unD + +instance (MapP phi f) => MapP phi ([] :.: f) where + mapP' f phi (CCL x p _) = liftM D . mapMwithI (\i -> + if i == length x + then mapP' f phi p + else return) . unD + + +mapPR :: forall phi top t a. (Fam phi, MapP phi (PF phi)) + => phi a -> Path phi t a + -> (phi t -> HWithRef phi top t -> Maybe (HWithRef phi top t)) + -> HWithRef phi top a -> Maybe (HWithRef phi top a) +mapPR _ _ _ (HIn (Ref _)) = Nothing +mapPR w1 Empty f a = f w1 a +mapPR w1 (Push w2 y p) f (HIn (InR a)) = + liftM (HIn . InR) . mapP' (\w -> mapPR w p f) w1 y $ a + +mapMwithI :: (Monad m, Traversable t) => (Int -> a -> m b) -> t a -> m (t b) +mapMwithI f ta = evalStateT (mapM g ta) 0 where + g a = do i <- get + put $ i+1 + lift $ f i a
− Generics/MultiRec/Transformations/RewriteRules.hs
@@ -1,59 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE GADTs #-}--module Generics.MultiRec.Transformations.RewriteRules (- Transformation, Transform, apply, insert, AnyInsert (..)- ) where--import Generics.MultiRec hiding ( foldM )-import Generics.MultiRec.Rewriting-import Generics.MultiRec.Zipper (Zipper, Loc, leave, enter, update)--import Data.Maybe ( fromJust )-import Control.Monad ( (>=>), foldM )------------------------------------------------------------------------------------- Patch------------------------------------------------------------------------------------ Basically, a class synonym-class (Zipper phi (PF phi), Rewrite phi) => Transform phi-instance Transform phi => Rewrite phi---- An edit is a list of:-type Transformation phi a = [ AnyInsert phi a ]---- Existential for insertion-data AnyInsert phi a where - AnyInsert ::- -- Proof- phi ix- -- A path to the location to edit- -> (Loc phi I0 a -> Maybe (Loc phi I0 a)) - -- The rewrite rule to apply there- -> Rule phi ix- -> AnyInsert phi a--insert :: El phi ix => (Loc phi I0 a -> Maybe (Loc phi I0 a)) -> Rule phi ix- -> AnyInsert phi a-insert = AnyInsert proof---- Patching is terribly simple: at the given locations, apply all the rules,--- then exit the zipper.-apply :: Transform phi => Transformation phi a -> phi a -> a -> Maybe a-apply rs p x = fmap leave $ foldM appRule (enter p x) rs- where appRule a (AnyInsert p' l r) = l a >>=- updateM (\p'' -> case eqS p' p'' of- Nothing -> const Nothing- Just Refl -> rewriteM r)--updateM :: (forall xi. phi xi -> xi -> Maybe xi)- -> Loc phi I0 ix -> Maybe (Loc phi I0 ix)--- updateM f (Loc p (I0 x) s) = f p x >>= \y -> Loc p (I0 y) s-updateM f = Just . update (\p -> maybe (error "updateM") id . f p)
− Generics/MultiRec/Transformations/TH.hs
@@ -1,241 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE PatternGuards #-}--module Generics.MultiRec.Transformations.TH ( - deriveRefRep, prefix, postfix- ) where--import Generics.MultiRec hiding (show)-import Generics.MultiRec.TH-import Language.Haskell.TH hiding (Stmt ())-import Generics.MultiRec.Transformations.Explicit-import Control.Monad-import Control.Applicative-import Debug.Trace---- | Derive data type with references and 'HasRef' instance. For a data type--- N the name of the constructor for a reference is RefN, and the given--- function is used to change the rest of the constructors and the data--- type name itself. For example, for the following definition:------ > data Tree = Leaf Int | Bin Tree Tree--- > data TreeAST :: * -> * where--- > Tree :: TreeAST Tree--- > $(deriveRefRep ''TreeAST (postfix "R"))------ The following data type is generated:------ > data TreeR = LeafR Int | BinR TreeR TreeR | RefTree Path--- > instance HasRef TreeAST-deriveRefRep :: Name -> (Name -> Name) -> Q [Dec]-deriveRefRep n namef =- do- info <- reify n- let ps = init (extractParameters info)- let nps = map (\ (n, ps) -> (remakeName n, ps)) (extractConstructorNames ps info)- let ns = map fst nps- d <- deriveDatas n namef ps ns- r <- deriveHasRef n namef ps ns- return $ d ++ r--prefix :: String -> Name -> Name-prefix pref n = mkName $ pref ++ nameBase n--postfix :: String -> Name -> Name-postfix post n = mkName $ nameBase n ++ post---- | Turn a record-constructor into a normal constructor by just--- removing all the field names.-stripRecordNames :: Con -> Con-stripRecordNames (RecC n f) =- NormalC n (map (\(_, s, t) -> (s, t)) f)-stripRecordNames c = c--unApp :: Type -> [Type]-unApp (AppT f a) = unApp f ++ [a]-unApp t = [t]---- | Process the reified info of the index GADT, and extract--- its constructor names, which are also the names of the datatypes--- that are part of the family.-extractConstructorNames :: [Name] -> Info -> [(Name, [Name])]-extractConstructorNames ps (TyConI (DataD _ _ _ cs _)) = concatMap extractFrom cs- where- extractFrom :: Con -> [(Name, [Name])]- extractFrom (ForallC _ eqs c) = map (\ (n, _) -> (n, concatMap extractEq eqs)) (extractFrom c)- extractFrom (InfixC _ n _) = [(n, [])]- extractFrom (RecC n _) = [(n, [])]- extractFrom (NormalC n []) = [(n, [])]- extractFrom _ = []-- extractEq :: Pred -> [Name]- extractEq (EqualP t1 t2) = filter (\ p -> p `elem` ps) (extractArgs t1 ++ extractArgs t2)- extractEq _ = []-- extractArgs :: Type -> [Name]- extractArgs (AppT x (VarT n)) = extractArgs x ++ [n]- extractArgs (VarT n) = [n]- extractArgs _ = []-extractConstructorNames _ _ = []---- | Process the reified info of the index GADT, and extract--- its type parameters.-extractParameters :: Info -> [Name]-extractParameters (TyConI (DataD _ _ ns _ _)) = concatMap extractFromBndr ns-extractParameters (TyConI (TySynD _ ns _)) = concatMap extractFromBndr ns-extractParameters _ = []--extractFromBndr :: TyVarBndr -> [Name]-extractFromBndr (PlainTV n) = [n]-extractFromBndr (KindedTV n _) = [n]--deriveDatas :: Name -> (Name -> Name) -> [Name] -> [Name] -> Q [Dec]-deriveDatas s namef ps ns = zipWithM (deriveData s namef ps ns) [0..] ns--deriveData :: Name -> (Name -> Name) -> [Name] -> [Name] -> Int -> Name -> Q Dec-deriveData s namef ps ns i n = do- let nm = namef n- i <- reify n- cons <- case i of- TyConI (DataD _ _ _ cs _) -> mapM (mkCon n namef ns) cs- r <- normalC (prefix "Ref" n) [return (NotStrict, ConT ''Path)]- dataD (cxt []) nm (typeVariables i) (map return $ r : cons) []--mkCon :: Name -> (Name -> Name) -> [Name] -> Con -> Q Con-mkCon t namef ns (NormalC a b) = normalC (namef a) (map f b) where- f :: (Strict, Type) -> Q (Strict, Type)- f (s,t) = g t >>= return . (,) s- g :: Type -> Q Type- g (ConT n) | remakeName n `elem` ns = return (ConT $ namef n)- g (AppT f a) = g a >>= return . AppT f- g x = return x--typeVariables :: Info -> [TyVarBndr]-typeVariables (TyConI (DataD _ _ tv _ _)) = tv-typeVariables (TyConI (NewtypeD _ _ tv _ _)) = tv-typeVariables _ = []--deriveHasRef :: Name -> (Name -> Name) -> [Name] -> [Name] -> Q [Dec]-deriveHasRef s namef ps ns =- do- let tyInsts = [tySynInstD ''RefRep [conT s, conT n] (conT $ namef n) | n <- ns]- fcs <- liftM concat $ zipWithM (mkFrom ns namef (length ns)) [0..] ns- tcs <- liftM concat $ zipWithM (mkTo ns namef (length ns)) [0..] ns- return <$>- instanceD (cxt []) (conT ''HasRef `appT` (foldl appT (conT s) (map varT ps)))- (tyInsts ++ [funD 'toRef tcs, funD 'fromRef fcs])--mkFrom :: [Name] -> (Name -> Name) -> Int -> Int -> Name -> Q [Q Clause]-mkFrom ns namef m i n = do- let wrapE e = conE 'HIn `appE` (conE 'InR `appE` lrE m i (conE 'Tag `appE` e))- i <- reify n- let dn = remakeName n- let r = clause [conP dn [], conP (prefix "Ref" dn) [varP (field 0)]]- (normalB $ conE 'HIn `appE` (conE 'Ref `appE` varE (field 0))) []- let b = case i of- TyConI (DataD _ _ _ cs _) ->- zipWith (fromCon wrapE ns dn namef (length cs)) [0..] cs- TyConI (TySynD t _ _) ->- [clause [conP dn [], varP (field 0)] (normalB (wrapE $ conE 'K `appE` varE (field 0))) []]- _ -> error "unknown construct"- return (r : b)--mkTo :: [Name] -> (Name -> Name) -> Int -> Int -> Name -> Q [Q Clause]-mkTo ns namef m i n = do- let wrapP p = conP 'HIn [conP 'InR [lrP m i (conP 'Tag [p])]]- i <- reify n- let dn = remakeName n- let r = clause [conP dn [], conP 'HIn [conP 'Ref [varP (field 0)]]] - (normalB $ conE (prefix "Ref" dn) `appE` varE (field 0)) []- let b = case i of- TyConI (DataD _ _ _ cs _) ->- zipWith (toCon wrapP ns dn namef (length cs)) [0..] cs- TyConI (TySynD t _ _) ->- [clause [conP dn [], wrapP $ conP 'K [varP (field 0)]] (normalB $ varE (field 0)) []]- _ -> error "unknown construct"- return (r : b)---fromCon :: (Q Exp -> Q Exp) -> [Name] -> Name -> (Name -> Name) -> Int -> Int -> Con -> Q Clause-fromCon wrap ns n namef m i (NormalC cn []) =- clause- [conP n [], conP (namef cn) []]- (normalB $ wrap $ lrE m i $ conE 'C `appE` (conE 'U)) []-fromCon wrap ns n namef m i (NormalC cn fs) =- -- runIO (putStrLn ("constructor " ++ show ix)) >>- clause- [conP n [], conP (namef cn) (map (varP . field) [0..length fs - 1])]- (normalB $ wrap $ lrE m i $ conE 'C `appE` foldr1 prod (zipWith (fromField ns) [0..] (map snd fs))) []- where- prod x y = conE '(:*:) `appE` x `appE` y-fromCon wrap ns n namef m i r@(RecC _ _) =- fromCon wrap ns n namef m i (stripRecordNames r)-fromCon wrap ns n namef m i (InfixC t1 cn t2) =- fromCon wrap ns n namef m i (NormalC cn [t1,t2])-fromCon wrap ns n namef m i (ForallC _ _ c) =- fromCon wrap ns n namef m i c--toCon :: (Q Pat -> Q Pat) -> [Name] -> Name -> (Name -> Name) -> Int -> Int -> Con -> Q Clause-toCon wrap ns n namef m i (NormalC cn []) =- clause- [conP n [], wrap $ lrP m i $ conP 'C [conP 'U []]]- (normalB $ conE $ namef cn) []-toCon wrap ns n namef m i (NormalC cn fs) =- -- runIO (putStrLn ("constructor " ++ show ix)) >>- clause- [conP n [], wrap $ lrP m i $ conP 'C [foldr1 prod (map (varP . field) [0..length fs - 1])]]- (normalB $ foldl appE (conE $ namef cn) (zipWith (toField ns) [0..] (map snd fs))) []- where- prod x y = conP '(:*:) [x,y]-toCon wrap ns n namef m i r@(RecC _ _) =- toCon wrap ns n namef m i (stripRecordNames r)-toCon wrap ns n namef m i (InfixC t1 cn t2) =- toCon wrap ns n namef m i (NormalC cn [t1,t2])-toCon wrap ns n namef m i (ForallC _ _ c) =- toCon wrap ns n namef m i c--fromField :: [Name] -> Int -> Type -> Q Exp-fromField ns nr t = [| $(fromFieldFun ns t) $(varE (field nr)) |]--fromFieldFun :: [Name] -> Type -> Q Exp-fromFieldFun ns t@(ConT n)- | remakeName n `elem` ns = [| I . fromRef $(conE $ remakeName n) |]-fromFieldFun ns t- | ConT n : a <- unApp t, remakeName n `elem` ns- = [| I . fromRef $(conE $ remakeName n) |]-fromFieldFun ns t@(AppT f a) = [| D . fmap $(fromFieldFun ns a) |]-fromFieldFun ns t = [| K |]--toField :: [Name] -> Int -> Type -> Q Exp-toField ns nr t = [| $(toFieldFun ns t) $(varE (field nr)) |]--toFieldFun :: [Name] -> Type -> Q Exp-toFieldFun ns t@(ConT n)- | remakeName n `elem` ns = [| toRef $(conE $ remakeName n) . unI |]-toFieldFun ns t- | ConT n : a <- unApp t, remakeName n `elem` ns- = [| toRef $(conE $ remakeName n) . unI |]-toFieldFun ns t@(AppT f a) = [| fmap $(toFieldFun ns a) . unD |]-toFieldFun ns t = [| unK |]--field :: Int -> Name-field n = mkName $ "f" ++ show n--lrP :: Int -> Int -> (Q Pat -> Q Pat)-lrP 1 0 p = p-lrP m 0 p = conP 'L [p]-lrP m i p = conP 'R [lrP (m-1) (i-1) p]--lrE :: Int -> Int -> (Q Exp -> Q Exp)-lrE 1 0 e = e-lrE m 0 e = conE 'L `appE` e-lrE m i e = conE 'R `appE` lrE (m-1) (i-1) e---- Should we, under certain circumstances, maintain the module name?-remakeName :: Name -> Name-remakeName n = mkName (nameBase n)
+ Generics/MultiRec/Transformations/ZipChildren.hs view
@@ -0,0 +1,94 @@+{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE ScopedTypeVariables #-} + +module Generics.MultiRec.Transformations.ZipChildren where + +import Generics.MultiRec hiding ( show, foldM ) +import Control.Monad.State hiding ( foldM, mapM ) +import Data.Foldable ( toList ) + +import Generics.MultiRec.CountIs +import Generics.MultiRec.Transformations.Path +import Generics.MultiRec.Transformations.Children +import Generics.MultiRec.Transformations.MemoTable + +-------------------------------------------------------------------------------- +-- Zip immediate children +-------------------------------------------------------------------------------- + +zipChildrenM :: (Monad m, Fam phi, ZipChildren phi (PF phi)) + => phi ix + -> (forall t. (Lookup phi (Ixs phi) t, Children phi (PF phi) t, GetChildrenTable phi (Ixs phi) t, Eq t) => phi t -> Path phi t ix -> t -> t -> m a) + -> ix + -> ix + -> m [a] +{- +zipChildrenM p f a b = zipChildren p (\p w (I0 l) (I0 r) -> f p w l r) + (\z -> Push p z Empty) + (from p a) (from p b) +-} +zipChildrenM p f a b = zipChildren p (\p w (I0 l) (I0 r) -> f p w l r) + (\z -> Push (error "oops") z Empty) + (from p a) (from p b) + +class ZipChildren phi (f :: (* -> *) -> * -> *) where + zipChildren :: (Monad m) + => phi ix + -> (forall t. (Lookup phi (Ixs phi) t, Children phi (PF phi) t, GetChildrenTable phi (Ixs phi) t, Eq t) + => phi t -> Path phi t ix -> r t -> r t -> m a) + -> (forall t. Dir f t ix -> Path phi t ix) + -> f r ix + -> f r ix + -> m [a] + +instance ( Lookup phi (Ixs phi) xi, El phi xi, Children phi (PF phi) xi + , GetChildrenTable phi (Ixs phi) xi, Eq xi) => ZipChildren phi (I xi) where + zipChildren _ f w (I l) (I r) = f proof (w CId) l r >>= \x -> return [x] + +instance ZipChildren phi (K a) where + zipChildren _ _ _ _ _ = return [] + +instance ZipChildren phi U where + zipChildren _ _ _ _ _ = return [] + +instance (ZipChildren phi f, ZipChildren phi g) => ZipChildren phi (f :+: g) where + zipChildren p f w (L l) (L r) = zipChildren p f (w . CL) l r + zipChildren p f w (R l) (R r) = zipChildren p f (w . CR) l r + +instance (ZipChildren phi f, ZipChildren phi g, CountIs g) + => ZipChildren phi (f :*: g) where + zipChildren p f w (l1 :*: l2) (r1 :*: r2) = + liftM2 (++) (zipChildren p f (\z -> w (C1 z nullY)) l1 r1) + (zipChildren p f (\z -> w (C2 nullX z)) l2 r2) + where nullX = error "nullX" -- fmap (const ()) x + nullY = error "nullY" -- fmap (const ()) y + +instance (ZipChildren phi f, Constructor c) => ZipChildren phi (C c f) where + zipChildren p f w (C l) (C r) = zipChildren p f (w . CC) l r + +instance ZipChildren phi f => ZipChildren phi (f :>: ix) where + zipChildren p f w (Tag l) (Tag r) = zipChildren p f (w . CTag) l r +{- +instance (Traversable t, ZipChildren phi f) => ZipChildren phi (t :.: f) where + zipChildren p f w (D l) (D r) = liftM concat $ sequence $ + zipWith3 (\i -> zipChildren p f (w . TrvI i)) + [0..] (toList l) (toList r) +-} +instance (ZipChildren phi f) => ZipChildren phi (Maybe :.: f) where + zipChildren p f w (D l) (D r) = liftM concat $ sequence $ + zipWith3 (\i -> zipChildren p f (w . CCM)) + [0..] (toList l) (toList r) + +instance (ZipChildren phi f) => ZipChildren phi ([] :.: f) where + zipChildren p f w (D l) (D r) = liftM concat $ sequence $ + zipWith3 (\i -> zipChildren p f (\x -> w (CCL (ll i) x lr))) + [0..] l r + where ll i = replicate i (error "oops3") + lr = error "oops2"
− Generics/MultiRec/Transformations/ZipperState.hs
@@ -1,72 +0,0 @@-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}--module Generics.MultiRec.Transformations.ZipperState (- ZipperMonad, ZipperState, upMonad, downMonad, leftMonad, rightMonad, - navigate, saveMonad, loadMonad, topMonad, updateMonad- ) where--import Control.Monad-import Control.Monad.State--import Generics.MultiRec-import Generics.MultiRec.Zipper-import Generics.MultiRec.Any------------------------------------------------------------------------------------- A zipper with state-----------------------------------------------------------------------------------type ZipperState phi r a = ([Any phi], Loc phi r a)-type ZipperMonad phi r a b = StateT (ZipperState phi r a) Maybe b--enterMonad :: (El phi a, Fam phi, Zipper phi (PF phi))- => a -> ZipperMonad phi I0 a (Any phi)-enterMonad x = put ([], enter proof x) >> return (Any proof x)--moveMonad :: (EqS phi, El phi a)- => (Loc phi I0 a -> Maybe (Loc phi I0 a))- -> ZipperMonad phi I0 a (Any phi)-moveMonad d = StateT (\(s,l) -> do l' <- d l- let a = on (\p (I0 x) -> Any p x) l'- return (a, (s,l')))--upMonad, downMonad, leftMonad, rightMonad :: (EqS phi, El phi a)- => ZipperMonad phi I0 a (Any phi)-upMonad = moveMonad up-downMonad = moveMonad down-leftMonad = moveMonad left-rightMonad = moveMonad right--updateMonad :: (EqS phi, El phi a)- => (forall xi. phi xi -> xi -> Maybe xi) - -> ZipperMonad phi I0 a (Any phi)-updateMonad f = do (s,l) <- get- let l' = update (\p -> maybe (error "updateMonad") id . f p) l- a = on (\p (I0 x) -> Any p x) l'- put (s,l')- return a-saveMonad :: (EqS phi, El phi a) => ZipperMonad phi I0 a (Any phi)-saveMonad = do (s,l) <- get- let a = on (\p (I0 x) -> Any p x) l- put (s++[a],l)- return a--loadMonad :: (EqS phi, El phi a) => ZipperMonad phi I0 a (Any phi)-loadMonad = do (s:ss,l) <- get- let l' = update (\p x -> maybe x id (matchAny p s)) l- put (ss,l')- return s--topMonad :: (EqS phi, El phi a) => ZipperMonad phi I0 a (Any phi)-topMonad = moveMonad goUp where- goUp l = maybe (Just l) goUp (up l)--leaveMonad :: (EqS phi, El phi a) - => Loc phi I0 a -> ZipperMonad phi I0 a b -> Maybe a-leaveMonad s m = maybe Nothing (matchAny proof) $ evalStateT (m >> topMonad) ([],s)--navigate :: (Fam phi, EqS phi, El phi a, Zipper phi (PF phi))- => phi a -> a -> ZipperMonad phi I0 a b -> Maybe a-navigate p x = leaveMonad (enter p x)
+ Generics/MultiRec/Zipper.hs view
@@ -0,0 +1,220 @@+{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE EmptyDataDecls #-} + +----------------------------------------------------------------------------- +-- | +-- Module : Generics.MultiRec.Zipper +-- Copyright : (c) 2008--2009 Universiteit Utrecht +-- License : BSD3 +-- +-- Maintainer : generics@haskell.org +-- Stability : experimental +-- Portability : non-portable +-- +-- +-- The generic zipper. +-- +----------------------------------------------------------------------------- + +module Generics.MultiRec.Zipper where + +import Prelude hiding (last) + +import Control.Monad +import Control.Applicative +import Data.Traversable + +import Generics.MultiRec.Base +import Generics.MultiRec.HFunctor + +-- * Locations and context stacks + +-- | Abstract type of locations. A location contains the current focus +-- and its context. A location is parameterized over the family of +-- datatypes and over the type of the complete value. + +data Loc :: (* -> *) -> (* -> *) -> * -> * where + Loc :: (Fam phi, Zipper phi (PF phi)) + => phi ix -> r ix -> Ctxs phi ix r a -> Loc phi r a + +data Ctxs :: (* -> *) -> * -> (* -> *) -> * -> * where + Empty :: Ctxs phi a r a + -- Push :: phi ix -> Ctx (PF phi) b r ix -> Ctxs phi ix r a -> Ctxs phi b r a + Push :: phi a -> Ctx (PF phi) a r ix -> Ctxs phi b r a -> Ctxs phi b r ix + +-- * Context frames + +-- | Abstract type of context frames. Not required for the high-level +-- navigation functions. + +data family Ctx (f :: (* -> *) -> * -> *) :: * -> (* -> *) -> * -> * + +data instance Ctx (K a) b r ix +data instance Ctx U b r ix +data instance Ctx (f :+: g) b r ix = CL (Ctx f b r ix) + | CR (Ctx g b r ix) +data instance Ctx (f :*: g) b r ix = C1 (Ctx f b r ix) (g r ix) + | C2 (f r ix) (Ctx g b r ix) + +data instance Ctx ([] :.: g) b r ix = CCL [g r ix] (Ctx g b r ix) [g r ix] +data instance Ctx (Maybe :.: g) b r ix = CCM (Ctx g b r ix) + + +data instance Ctx (I xi) b r ix where CId :: Ctx (I xi) xi r ix +data instance Ctx (f :>: xi) b r ix where + CTag :: Ctx f b r ix -> Ctx (f :>: ix) b r ix +data instance Ctx (C c f) b r ix = CC (Ctx f b r ix) + +-- * Contexts and locations are functors + +instance Zipper phi f => HFunctor phi (Ctx f b) where + hmapA = cmapA + +instance Zipper phi (PF phi) => HFunctor phi (Ctxs phi b) where + hmapA f p' Empty = pure Empty + -- hmapA f p' (Push p c s) = liftA2 (Push p) (hmapA f p c) (hmapA f p' s) + hmapA f p' (Push p c s) = liftA2 (Push p) (hmapA f p' c) (hmapA f p s) + +instance HFunctor phi (Loc phi) where + hmapA f p' (Loc p x s) = liftA2 (Loc p) (f p x) (hmapA f p' s) + +-- * Generic navigation functions + +-- | It is in general not necessary to use the generic navigation +-- functions directly. The functions listed in the ``Interface'' section +-- below are more user-friendly. +-- + +class HFunctor phi f => Zipper phi f where + cmapA :: Applicative a => (forall ix. phi ix -> r ix -> a (r' ix)) -> + phi ix -> Ctx f b r ix -> a (Ctx f b r' ix) + fill :: phi b -> Ctx f b r ix -> r b -> f r ix + first, last :: (forall b. phi b -> r b -> Ctx f b r ix -> a) + -> f r ix -> Maybe a + next, prev :: (forall b. phi b -> r b -> Ctx f b r ix -> a) + -> phi b -> Ctx f b r ix -> r b -> Maybe a + +instance El phi xi => Zipper phi (I xi) where + cmapA f p CId = pure CId + fill p CId x = I x + first f (I x) = return (f proof x CId) + last f (I x) = return (f proof x CId) + next f p CId x = Nothing + prev f p CId x = Nothing + +instance Zipper phi (K a) where + cmapA f p void = impossible void + fill p void x = impossible void + first f (K a) = Nothing + last f (K a) = Nothing + next f p void x = impossible void + prev f p void x = impossible void + +instance Zipper phi U where + cmapA f p void = impossible void + fill p void x = impossible void + first f U = Nothing + last f U = Nothing + next f p void x = impossible void + prev f p void x = impossible void + +instance (Zipper phi f, Zipper phi g) => Zipper phi (f :+: g) where + cmapA f p (CL c) = liftA CL (cmapA f p c) + cmapA f p (CR c) = liftA CR (cmapA f p c) + fill p (CL c) x = L (fill p c x) + fill p (CR c) y = R (fill p c y) + first f (L x) = first (\p z -> f p z . CL) x + first f (R y) = first (\p z -> f p z . CR) y + last f (L x) = last (\p z -> f p z . CL) x + last f (R y) = last (\p z -> f p z . CR) y + next f p (CL c) x = next (\p z -> f p z . CL) p c x + next f p (CR c) y = next (\p z -> f p z . CR) p c y + prev f p (CL c) x = prev (\p z -> f p z . CL) p c x + prev f p (CR c) y = prev (\p z -> f p z . CR) p c y + +instance (Zipper phi f, Zipper phi g) => Zipper phi (f :*: g) where + cmapA f p (C1 c y) = liftA2 C1 (cmapA f p c) (hmapA f p y) + cmapA f p (C2 x c) = liftA2 C2 (hmapA f p x) (cmapA f p c) + fill p (C1 c y) x = fill p c x :*: y + fill p (C2 x c) y = x :*: fill p c y + first f (x :*: y) = + first (\p z c -> f p z (C1 c y )) x `mplus` + first (\p z c -> f p z (C2 x c )) y + last f (x :*: y) = + last (\p z c -> f p z (C2 x c )) y `mplus` + last (\p z c -> f p z (C1 c y )) x + next f p (C1 c y) x = + next (\p' z c' -> f p' z (C1 c' y )) p c x `mplus` + first (\p' z c' -> f p' z (C2 (fill p c x) c')) y + next f p (C2 x c) y = + next (\p' z c' -> f p' z (C2 x c')) p c y + prev f p (C1 c y) x = + prev (\p' z c' -> f p' z (C1 c' y )) p c x + prev f p (C2 x c) y = + prev (\p' z c' -> f p' z (C2 x c')) p c y `mplus` + last (\p' z c' -> f p' z (C1 c' (fill p c y))) x + +-- For the time being, we support just [] and Maybe. I think we +-- might be able to support a whole class (Foldable). +instance (Zipper phi g) => Zipper phi ([] :.: g) where + cmapA f p (CCL pb c pe) = + CCL <$> traverse (hmapA f p) pb <*> cmapA f p c <*> traverse (hmapA f p) pe + fill p (CCL pb c pe) x = + D (reverse pb ++ fill p c x : pe) + first f (D []) = Nothing + first f (D (x : xs)) = first (\p z c -> f p z (CCL [] c xs)) x + last f (D xs) = + case reverse xs of + [] -> Nothing + y : ys -> last (\p z c -> f p z (CCL ys c [])) y + next f p (CCL pb c pe) x = + next (\p z c -> f p z (CCL pb c pe)) p c x `mplus` + case pe of + [] -> Nothing + y : ys -> first (\p' z c' -> f p' z (CCL (fill p c x : pb) c' ys)) y + prev f p (CCL pb c pe) x = + prev (\p z c -> f p z (CCL pb c pe)) p c x `mplus` + case pb of + [] -> Nothing + y : ys -> last (\p' z c' -> f p' z (CCL ys c' (fill p c x : pe))) y + +instance (Zipper phi g) => Zipper phi (Maybe :.: g) where + cmapA f p (CCM c) = + CCM <$> cmapA f p c + fill p (CCM c) x = + D (Just (fill p c x)) + first f (D Nothing) = Nothing + first f (D (Just x)) = first (\p z -> f p z . CCM) x + last f (D Nothing) = Nothing + last f (D (Just x)) = last (\p z -> f p z . CCM) x + next f p (CCM c) x = next (\p z -> f p z . CCM) p c x + prev f p (CCM c) x = prev (\p z -> f p z . CCM) p c x + +instance Zipper phi f => Zipper phi (f :>: xi) where + cmapA f p (CTag c) = liftA CTag (cmapA f p c) + fill p (CTag c) x = Tag (fill p c x) + first f (Tag x) = first (\p z -> f p z . CTag) x + last f (Tag x) = last (\p z -> f p z . CTag) x + next f p (CTag c) x = next (\p z -> f p z . CTag) p c x + prev f p (CTag c) x = prev (\p z -> f p z . CTag) p c x + +instance (Constructor c, Zipper phi f) => Zipper phi (C c f) where + cmapA f p (CC c) = liftA CC (cmapA f p c) + fill p (CC c) x = C (fill p c x) + first f (C x) = first (\p z -> f p z . CC) x + last f (C x) = last (\p z -> f p z . CC) x + next f p (CC c) x = next (\p z -> f p z . CC) p c x + prev f p (CC c) x = prev (\p z -> f p z . CC) p c x + + +-- * Internal functions + +impossible :: a -> b +impossible x = error "impossible"
Generics/Regular/Functions/GOrd.hs view
@@ -1,41 +1,41 @@-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE FlexibleContexts #-}--module Generics.Regular.Functions.GOrd where--import Generics.Regular-import Data.Monoid (mappend)------------------------------------------------------------------------------------- Generic Ord-----------------------------------------------------------------------------------class GOrd f where- comparef :: (a -> a -> Ordering) -> f a -> f a -> Ordering--instance GOrd I where- comparef f (I x) (I y) = f x y--instance Ord a => GOrd (K a) where- comparef _ (K x) (K y) = compare x y--instance GOrd U where- comparef _ U U = EQ--instance (GOrd f, GOrd g) => GOrd (f :+: g) where- comparef _ (L _) (R _) = LT- comparef _ (R _) (L _) = GT- comparef f (L x) (L y) = comparef f x y- comparef f (R x) (R y) = comparef f x y--instance (GOrd f, GOrd g) => GOrd (f :*: g) where- comparef f (x1 :*: y1) (x2 :*: y2) = comparef f x1 x2 `mappend` comparef f y1 y2--instance GOrd f => GOrd (C c f) where- comparef f (C x) (C y) = comparef f x y--instance GOrd f => GOrd (S s f) where- comparef f (S x) (S y) = comparef f x y--gcompare :: (Regular a, GOrd (PF a)) => a -> a -> Ordering-gcompare x y = comparef gcompare (from x) (from y)+{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE FlexibleContexts #-} + +module Generics.Regular.Functions.GOrd where + +import Generics.Regular +import Data.Monoid (mappend) + +-------------------------------------------------------------------------------- +-- Generic Ord +-------------------------------------------------------------------------------- + +class GOrd f where + comparef :: (a -> a -> Ordering) -> f a -> f a -> Ordering + +instance GOrd I where + comparef f (I x) (I y) = f x y + +instance Ord a => GOrd (K a) where + comparef _ (K x) (K y) = compare x y + +instance GOrd U where + comparef _ U U = EQ + +instance (GOrd f, GOrd g) => GOrd (f :+: g) where + comparef _ (L _) (R _) = LT + comparef _ (R _) (L _) = GT + comparef f (L x) (L y) = comparef f x y + comparef f (R x) (R y) = comparef f x y + +instance (GOrd f, GOrd g) => GOrd (f :*: g) where + comparef f (x1 :*: y1) (x2 :*: y2) = comparef f x1 x2 `mappend` comparef f y1 y2 + +instance GOrd f => GOrd (C c f) where + comparef f (C x) (C y) = comparef f x y + +instance GOrd f => GOrd (S s f) where + comparef f (S x) (S y) = comparef f x y + +gcompare :: (Regular a, GOrd (PF a)) => a -> a -> Ordering +gcompare x y = comparef gcompare (from x) (from y)
− Generics/Regular/Transformations/Explicit.hs
@@ -1,357 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE TypeFamilies #-}--module Generics.Regular.Transformations.Explicit (- diff, apply, Transformation, WithRef (..), Path, Transform, - HasRef (..), NiceTransformation, toNiceTransformation, fromNiceTransformation- ) where--import Generics.Regular-import Generics.Regular.Functions.GOrd-import Control.Applicative ( (<|>) )-import Control.Monad (foldM, liftM, liftM2)-import Control.Monad.State-import Data.Monoid (mappend)-import qualified Data.Map as Map-import Data.Map (Map)-import qualified Generics.Regular.Functions.Eq as GEq------------------------------------------------------------------------------------- Paths, annotations and edits----------------------------------------------------------------------------------type Path = [Int]-data WithRef a b = InR (PF a b)- | Ref Path--instance Functor (PF a) => Functor (WithRef a) where- fmap f (InR x) = InR (fmap f x)- fmap _ (Ref p) = Ref p--type Transformation a = [ (Path, Fix (WithRef a)) ]--class (Regular a, Children (PF a), CountI (PF a), Functor (PF a),- SEq (PF a), ExtractN (PF a), MapN (PF a), GMap (PF a), GOrd (PF a),- GEq.Eq (PF a)) => Transform a------------------------------------------------------------------------------------- Patching------------------------------------------------------------------------------------- | Apply the edits to the given tree-apply :: Transform a => Transformation a -> a -> Maybe a-apply e t = foldM apply' t e where- apply' _ ([], c) = lookupRefs t c- apply' a (i:is, c) = fmap to . tmapN f . from $ a where- f j x | i == j = apply' x (is,c)- | otherwise = Just x---- | Look up the references using the original structure-lookupRefs :: Transform a => a -> Fix (WithRef a) -> Maybe a-lookupRefs r (In (InR a)) = fmap to (fmapM (lookupRefs r) a)-lookupRefs r (In (Ref p)) = extract p r---- | Extract the subtree at the given path-extract :: Transform a => Path -> a -> Maybe a-extract p a = foldM (\x i -> extractN i $ from x) a p------------------------------------------------------------------------------------- Diffing----------------------------------------------------------------------------------data MemoKey a where- MemoKey :: Bool -> a -> a -> MemoKey a--instance (Regular a, GEq.Eq (PF a)) => Eq (MemoKey a) where- (MemoKey a1 b1 c1) == (MemoKey a2 b2 c2) =- a1 == a2 && GEq.eq b1 b2 && GEq.eq c1 c2--instance (Regular a, GEq.Eq (PF a), GOrd (PF a)) => Ord (MemoKey a) where- compare (MemoKey a1 b1 c1) (MemoKey a2 b2 c2) =- compare a1 a2 `mappend` gcompare b1 b2 `mappend` gcompare c1 c2--type Memo a = Map (MemoKey a) (Transformation a)---- | Find a set of edits to transform the first into the second tree-diff :: forall a. (Transform a) => a -> a -> Transformation a-diff a b = evalState (build False a b) Map.empty- where- childPaths :: [(a,Path)]- childPaths = childrenPaths a- buildmem :: Bool -> a -> a -> State (Memo a) (Transformation a)- buildmem a b c = do- mp <- get- let k = MemoKey a b c- case Map.lookup k mp of- Just r -> return r- Nothing -> do- r <- build a b c- modify (Map.insert k r)- return r- build :: Bool -> a -> a -> State (Memo a) (Transformation a)- build False a' b' | GEq.eq a' b' = return []- build ins a' b' = case lookupWith GEq.eq b' childPaths of- Just p -> return [([], In (Ref p))]- Nothing -> uses >>= maybe insert return- where- -- Construct the edits for the children based on a root- construct :: Bool -> a -> State (Memo a) (Maybe (Transformation a))- construct ins' c =- if shallowEq (from c) (from b')- then do r <- zipWithM (buildmem ins') (imChildren c) (imChildren b')- return $ Just $ concat $ updateChildPaths r- else return Nothing- -- Possible edits reusing the existing tree or using a part of- -- the original tree. The existing tree is only used if we didn't- -- just insert it, since we want to keep the inserts small- uses :: State (Memo a) (Maybe (Transformation a))- uses = reuses >>= \re -> case re of- Just r | ins -> return re- _ -> construct ins a' >>= return . best re- -- Possible edits that include reusing a part of the original tree- reuses :: State (Memo a) (Maybe (Transformation a))- reuses = foldM f Nothing childPaths where- addRef p = fmap (([], In (Ref p)):)- f c (x,p) = construct False x >>= return . best c . addRef p- -- Best edit including insertion, only chosen if nothing can be reused- insert :: State (Memo a) (Transformation a)- insert = do- Just r <- construct True b'- let (r', e') = partialApply (withRefs b') r- return $ ([], r') : e'---- | Helper function for lookup with provided compare function-lookupWith :: (a -> a -> Bool) -> a -> [(a,b)] -> Maybe b-lookupWith _ _ [] = Nothing-lookupWith f a ((b,r):bs)- | f a b = Just r- | otherwise = lookupWith f a bs---- | Pick the best edit-best :: Maybe (Transformation a) -> Maybe (Transformation a) -> Maybe (Transformation a)-best e1 e2 = case (e1,e2) of- (Just e1', Just e2') -> Just (pickShortest e1' e2')- _ -> e1 <|> e2---- | Pick the shortest of two lists lazily-pickShortest :: [a] -> [a] -> [a]-pickShortest a b = if f a b then a else b- where f [] _ = True- f _ [] = False- f (_:xs) (_:ys) = f xs ys---- | Lift a tree to a tree with references-withRefs :: Transform a => a -> Fix (WithRef a)-withRefs = In . InR . fmap withRefs . from---- | Try to apply as much edits to the edit structure as possible--- to make the final edit smaller-partialApply :: Transform a =>- Fix (WithRef a) -> Transformation a -> (Fix (WithRef a), Transformation a)-partialApply a [] = (a, [])-partialApply a ((p,r):xs) = case replace p r a of- Just a' -> partialApply a' xs- Nothing -> let (a',xs') = partialApply a xs in (a', (p,r) : xs')---- | Replace a subtree in an edit structure-replace :: (Transform a, Monad m)- => Path -> Fix (WithRef a) -> Fix (WithRef a) -> m (Fix (WithRef a))-replace [] r _ = return r-replace (i:is) r a = case a of- In (Ref _) -> fail "Replace"- In (InR a') -> tmapN f a' >>= return . In . InR- where f j = if i == j then replace is r else return---- | Extend the paths of edits for the children with the child number-updateChildPaths :: [Transformation a] -> [Transformation a]-updateChildPaths = zipWith (\n -> map (\(p,c) -> (n:p,c))) [0..]------------------------------------------------------------------------------------- Shallow equality-----------------------------------------------------------------------------------class SEq f where- shallowEq :: f a -> f a -> Bool--instance SEq I where- shallowEq (I _) (I _) = True--instance SEq U where- shallowEq U U = True--instance Eq a => SEq (K a) where- shallowEq (K a) (K b) = a == b--instance (SEq f, SEq g) => SEq (f :+: g) where- shallowEq (L a) (L b) = shallowEq a b- shallowEq (R a) (R b) = shallowEq a b- shallowEq _ _ = False--instance (SEq f, SEq g) => SEq (f :*: g) where- shallowEq (a :*: b) (c :*: d) = shallowEq a c && shallowEq b d--instance SEq f => SEq (C c f) where- shallowEq (C a) (C b) = shallowEq a b--instance SEq f => SEq (S s f) where- shallowEq (S a) (S b) = shallowEq a b------------------------------------------------------------------------------------- ExtractN-----------------------------------------------------------------------------------class ExtractN f where- extractN :: Monad m => Int -> f a -> m a--instance ExtractN I where- extractN 0 (I r) = return r- extractN _ (I _) = fail "extractN"--instance ExtractN (K a) where- extractN _ (K _) = fail "extractN"--instance ExtractN U where- extractN _ U = fail "extractN"--instance (ExtractN f, ExtractN g) => ExtractN (f :+: g) where- extractN i (L x) = extractN i x- extractN i (R x) = extractN i x---- Here we decrement our parameter. Does not require right-nested products-instance (CountI f, ExtractN f, ExtractN g) => ExtractN (f :*: g) where- extractN i (x :*: y) = let n = countI x- in if i < n then extractN i x- else extractN (i-n) y--instance ExtractN f => ExtractN (C c f) where- extractN i (C x) = extractN i x--instance ExtractN f => ExtractN (S s f) where- extractN i (S x) = extractN i x------------------------------------------------------------------------------------- MapN------------------------------------------------------------------------------------- | Map a function with child index at a top-level structure-tmapN :: (Monad m, MapN f) => (Int -> a -> m b) -> f a -> m (f b)-tmapN = mapN 0--class MapN f where- mapN :: Monad m => Int -> (Int -> a -> m b) -> f a -> m (f b)--instance MapN I where- mapN i f (I r) = liftM I (f i r)--instance MapN (K a) where- mapN _ _ (K x) = liftM K (return x)--instance MapN U where- mapN _ _ U = return U--instance (MapN f, MapN g) => MapN (f :+: g) where- mapN i f (L x) = liftM L (mapN i f x)- mapN i f (R x) = liftM R (mapN i f x)---- Here we increment our parameter. Does not require right-nested products-instance (CountI f, MapN f, MapN g) => MapN (f :*: g) where- mapN i f (x :*: y) = liftM2 (:*:) (mapN i f x) (mapN (i + countI x) f y)--instance MapN f => MapN (C c f) where- mapN i f (C x) = liftM C (mapN i f x)--instance MapN f => MapN (S s f) where- mapN i f (S x) = liftM S (mapN i f x)-------------------------------------------------------------------------------------- CountI-----------------------------------------------------------------------------------class CountI f where- -- | Count the number of recursive occurrences- countI :: f a -> Int--instance CountI I where- countI _ = 1--instance CountI (K a) where- countI _ = 0--instance CountI U where- countI _ = 0--instance (CountI f, CountI g) => CountI (f :+: g) where- countI (L x) = countI x- countI (R x) = countI x--instance (CountI f, CountI g) => CountI (f :*: g) where- countI (x :*: y) = countI x + countI y--instance CountI f => CountI (C c f) where- countI (C x) = countI x--instance CountI f => CountI (S s f) where- countI (S x) = countI x------------------------------------------------------------------------------------- Children------------------------------------------------------------------------------------- | Get the immediate children-imChildren :: (Regular a, Children (PF a)) => a -> [a]-imChildren = children . from---- | Get all children with their paths-childrenPaths :: (Regular a, Children (PF a)) => a -> [(a,Path)]-childrenPaths a = (a, []) : [ (r, n : p)- | (n, c) <- zip [0..] (imChildren a)- , (r, p) <- childrenPaths c ]--class Children f where- children :: f a -> [a]--instance Children I where- children (I r) = [r]--instance Children (K a) where- children (K _) = []--instance Children U where- children U = []--instance (Children f, Children g) => Children (f :+: g) where- children (L x) = children x- children (R x) = children x--instance (Children f, Children g) => Children (f :*: g) where- children (x :*: y) = children x ++ children y--instance Children f => Children (C c f) where- children (C x) = children x--instance Children f => Children (S s f) where- children (S x) = children x------------------------------------------------------------------------------------- Nicer interface----------------------------------------------------------------------------------class HasRef a where- type RefRep a- - toRef :: WithRef a (RefRep a) -> RefRep a- fromRef :: RefRep a -> WithRef a (RefRep a)--type NiceTransformation a = [ (Path, RefRep a) ] --toNiceTransformation :: (Functor (PF a), HasRef a) - => Transformation a -> NiceTransformation a-toNiceTransformation = map (\(p,e) -> (p, tr e)) where- tr = toRef . fmap tr . out--fromNiceTransformation :: (Functor (PF a), HasRef a) - => NiceTransformation a -> Transformation a-fromNiceTransformation = map (\(p,e) -> (p, fr e)) where- fr = In . fmap fr . fromRef
+ Generics/Regular/Transformations/Main.hs view
@@ -0,0 +1,451 @@+{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE UndecidableInstances #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE GeneralizedNewtypeDeriving #-} +{-# LANGUAGE TypeSynonymInstances #-} +{-# LANGUAGE OverlappingInstances #-} + +module Generics.Regular.Transformations.Main + ( diff, apply + , Transformation, WithRef (..), Path (..), Transform, HasRef (..) + , NiceTransformation, toNiceTransformation, fromNiceTransformation + ) where + +import Prelude as P +import Generics.Regular +import Generics.Regular.Functions.Show hiding ( show, shows, Show ) +import qualified Generics.Regular.Functions.Show as R +import Generics.Regular.Zipper +import Generics.Regular.Functions.GOrd +import Control.Applicative ( (<|>) ) +import Control.Monad (foldM, liftM, liftM2) +import Control.Monad.State +import Data.Monoid (mappend) +import qualified Data.Map as Map +import Data.Map (Map) +import qualified Generics.Regular.Functions.Eq as GEq + +-------------------------------------------------------------------------------- +-- Paths, annotations and edits +-------------------------------------------------------------------------------- +type Path a = [Dir (PF a)] +type Dir f = Ctx f () + +data WithRef a b = InR (PF a b) + | Ref (Path a) + +instance Functor (PF a) => Functor (WithRef a) where + fmap f (InR x) = InR (fmap f x) + fmap _ (Ref p) = Ref p -- ? + +type Transformation a = [ (Path a, Fix (WithRef a)) ] + +class (Regular a, Children (PF a), Functor (PF a), ZipChildren (PF a), + SEq (PF a), ExtractP (PF a), MapP (PF a), GMap (PF a), GOrd (PF a), + GEq.Eq (PF a)) => Transform a + +-------------------------------------------------------------------------------- +-- Showing paths +-------------------------------------------------------------------------------- +newtype ConIndex = CI Int deriving (Eq, Num) + +instance Show ConIndex where + show (CI (-1)) = "" + show (CI n ) = "_" ++ show n ++ " " + +class ShowPath f where + showsPrecPath :: ShowS -> ConIndex -> Int -> Dir f -> ShowS + +instance (ShowPath f, ShowPath g) => ShowPath (f :+: g) where + showsPrecPath r d n (CL p) = showsPrecPath r d n p + showsPrecPath r d n (CR p) = showsPrecPath r d n p + +instance (ShowPath f, ShowPath g, CountIs g) => ShowPath (f :*: g) where + -- Going left on a product is unproblematic + showsPrecPath r d n (C1 p _) = showsPrecPath r d n p + -- Going right, however, we have to increase |d| by the number of children to + -- our left + showsPrecPath r d n (C2 _ (p :: Ctx g ())) = + let newd = d + CI (countIs (undefined :: g r)) + in showsPrecPath r newd n p + +instance (ShowPath f, Constructor c) => ShowPath (C c f) where + showsPrecPath r d n (CC p) = let name = conName (undefined :: C c f r) + in showParen (n > 10) $ showString name + . showsPrecPath r 0 11 p + +instance ShowPath (K a) where showsPrecPath _ _ _ _ = id +instance ShowPath U where showsPrecPath _ _ _ _ = id + +instance ShowPath I where + showsPrecPath r d n CId = shows d . r + +showsPrecPathC :: (ShowPath f) => ConIndex -> Int -> [Dir f] -> ShowS +showsPrecPathC d n [] = showString "End" +showsPrecPathC d n (p:ps) = showsPrecPath (showsPrecPathC d n ps) d n p + +instance (ShowPath f) => Show [Dir f] where + showsPrec = showsPrecPathC 0 + +instance (ShowPath (PF a), Functor (PF a), R.Show (PF a)) + => Show (Fix (WithRef a)) where + showsPrec n (In (Ref p)) = showParen (n > 10) + $ showString "Ref " . showsPrec 11 p + showsPrec n (In (InR x)) = showParen (n > 10) + $ showString "InR " . R.hshowsPrec showsPrec False 11 x + +spaces :: [ShowS] -> ShowS +spaces = intersperse " " + +intersperse :: String -> [ShowS] -> ShowS +intersperse s [] = id +intersperse s [x] = x +intersperse s (x:xs) = x . (s ++) . spaces xs + +class CountIs f where + countIs :: f r -> Int + +instance CountIs I where countIs _ = 1 +instance CountIs U where countIs _ = 0 +instance CountIs (K a) where countIs _ = 0 + +instance (CountIs f) => CountIs (C c f) where + countIs (C x) = countIs x + +instance (CountIs f, CountIs g) => CountIs (f :+: g) where + countIs (L x) = countIs x + countIs (R x) = countIs x + +instance (CountIs f, CountIs g) => CountIs (f :*: g) where + countIs (x :*: y) = countIs x + countIs y + +-------------------------------------------------------------------------------- +-- Patching +-------------------------------------------------------------------------------- + +-- | Apply the edits to the given tree +apply :: Transform a => Transformation a -> a -> Maybe a +apply e t = foldM apply' t e where + apply' a (p, c) = mapP (flip lookupRefs c) p a + +-- | Look up the references using the original structure +lookupRefs :: Transform a => a -> Fix (WithRef a) -> Maybe a +lookupRefs r (In (InR a)) = fmap to (fmapM (lookupRefs r) a) +lookupRefs r (In (Ref p)) = extract p r + +-------------------------------------------------------------------------------- +-- Diffing +-------------------------------------------------------------------------------- +data MemoKey a where + MemoKey :: Bool -> a -> a -> MemoKey a + +instance (Regular a, GEq.Eq (PF a)) => Eq (MemoKey a) where + (MemoKey a1 b1 c1) == (MemoKey a2 b2 c2) = + a1 == a2 && GEq.eq b1 b2 && GEq.eq c1 c2 + +instance (Regular a, GEq.Eq (PF a), GOrd (PF a)) => Ord (MemoKey a) where + compare (MemoKey a1 b1 c1) (MemoKey a2 b2 c2) = + compare a1 a2 `mappend` gcompare b1 b2 `mappend` gcompare c1 c2 + +type Memo a = Map (MemoKey a) (Transformation a) + +-- | Find a set of edits to transform the first into the second tree +diff :: forall a. (Transform a) => a -> a -> Transformation a +diff a b = evalState (build False a b) Map.empty + where + childPaths :: [(a,Path a)] + childPaths = childrenPaths a + buildmem :: Bool -> a -> a -> State (Memo a) (Transformation a) + buildmem a b c = do + mp <- get + let k = MemoKey a b c + case Map.lookup k mp of + Just r -> return r + Nothing -> do + r <- build a b c + modify (Map.insert k r) + return r + build :: Bool -> a -> a -> State (Memo a) (Transformation a) + build False a' b' | GEq.eq a' b' = return [] + build ins a' b' = case lookupWith GEq.eq b' childPaths of + Just p -> return [([], In (Ref p))] + Nothing -> uses >>= maybe insert return + where + -- Construct the edits for the children based on a root + construct :: Bool -> a -> State (Memo a) (Maybe (Transformation a)) + construct ins' c = + if shallowEq (from c) (from b') + then do r <- zipChildrenM (\p c1 c2 -> buildmem ins' c1 c2 >>= + return . updateChildPaths p) c b' + return $ Just $ concat r + else return Nothing + -- Possible edits reusing the existing tree or using a part of + -- the original tree. The existing tree is only used if we didn't + -- just insert it, since we want to keep the inserts small + uses :: State (Memo a) (Maybe (Transformation a)) + uses = reuses >>= \re -> case re of + Just r | ins -> return re + _ -> construct ins a' >>= return . best re + -- Possible edits that include reusing a part of the original tree + reuses :: State (Memo a) (Maybe (Transformation a)) + reuses = foldM f Nothing childPaths where + addRef p = fmap (([], In (Ref p)):) + f c (x,p) = construct False x >>= return . best c . addRef p + -- Best edit including insertion, only chosen if nothing can be reused + insert :: State (Memo a) (Transformation a) + insert = do + Just r <- construct True b' + let (r', e') = partialApply (withRefs b') r + return $ ([], r') : e' + +-- | Helper function for lookup with provided compare function +lookupWith :: (a -> a -> Bool) -> a -> [(a,b)] -> Maybe b +lookupWith _ _ [] = Nothing +lookupWith f a ((b,r):bs) + | f a b = Just r + | otherwise = lookupWith f a bs + +-- | Pick the best edit +best :: Maybe (Transformation a) -> Maybe (Transformation a) -> Maybe (Transformation a) +best e1 e2 = case (e1,e2) of + (Just e1', Just e2') -> Just (pickShortest e1' e2') + _ -> e1 <|> e2 + +-- | Pick the shortest of two lists lazily +pickShortest :: [a] -> [a] -> [a] +pickShortest a b = if f a b then a else b + where f [] _ = True + f _ [] = False + f (_:xs) (_:ys) = f xs ys + +-- | Lift a tree to a tree with references +withRefs :: Transform a => a -> Fix (WithRef a) +withRefs = In . InR . fmap withRefs . from + +-- | Try to apply as much edits to the edit structure as possible +-- to make the final edit smaller +partialApply :: Transform a => + Fix (WithRef a) -> Transformation a -> (Fix (WithRef a), Transformation a) +partialApply a [] = (a, []) +partialApply a ((p,r):xs) = case replace p r a of + Just a' -> partialApply a' xs + Nothing -> let (a',xs') = partialApply a xs in (a', (p,r) : xs') + +-- | Replace a subtree in an edit structure +replace :: (Transform a, Monad m) + => Path a -> Fix (WithRef a) -> Fix (WithRef a) -> m (Fix (WithRef a)) +replace p r a = mapPR (const (return r)) p a + +-- | Extend the paths of edits for the children with the child number +updateChildPaths :: Path a -> Transformation a -> Transformation a +updateChildPaths p = map (\(p2,c) -> (p ++ p2,c)) +-------------------------------------------------------------------------------- +-- Shallow equality +-------------------------------------------------------------------------------- + +class SEq f where + shallowEq :: f a -> f a -> Bool + +instance SEq I where + shallowEq (I _) (I _) = True + +instance SEq U where + shallowEq U U = True + +instance Eq a => SEq (K a) where + shallowEq (K a) (K b) = a == b + +instance (SEq f, SEq g) => SEq (f :+: g) where + shallowEq (L a) (L b) = shallowEq a b + shallowEq (R a) (R b) = shallowEq a b + shallowEq _ _ = False + +instance (SEq f, SEq g) => SEq (f :*: g) where + shallowEq (a :*: b) (c :*: d) = shallowEq a c && shallowEq b d + +instance SEq f => SEq (C c f) where + shallowEq (C a) (C b) = shallowEq a b + +instance SEq f => SEq (S s f) where + shallowEq (S a) (S b) = shallowEq a b + +-------------------------------------------------------------------------------- +-- Extract +-------------------------------------------------------------------------------- +-- | Extract the subtree at the given path +extract :: (Transform a, Monad m) => Path a -> a -> m a +extract [] = return +extract (p:ps) = extractP (extract ps) p . from + +class ExtractP f where + extractP :: Monad m => (a -> m a) -> Dir f -> f a -> m a + +instance ExtractP I where + extractP f CId (I r) = f r + +instance ExtractP (K a) where + extractP _ _ (K _) = fail "extractP" + +instance ExtractP U where + extractP _ _ U = fail "extractP" + +instance (ExtractP f, ExtractP g) => ExtractP (f :+: g) where + extractP f (CL p) (L x) = extractP f p x + extractP f (CR p) (R x) = extractP f p x + extractP _ _ _ = fail "extractP" + +instance (ExtractP f, ExtractP g) => ExtractP (f :*: g) where + extractP f (C1 p _) (x :*: _) = extractP f p x + extractP f (C2 _ p) (_ :*: y) = extractP f p y + +instance ExtractP f => ExtractP (C c f) where + extractP f (CC p) (C x) = extractP f p x + +instance ExtractP f => ExtractP (S s f) where + extractP f (CS p) (S x) = extractP f p x + +-------------------------------------------------------------------------------- +-- MapP +-------------------------------------------------------------------------------- +-- | Map a function over the child in a specific path + +mapP :: (MapP (PF a), Monad m, Regular a) => (a -> m a) -> Path a -> a -> m a +mapP f [] = f +mapP f (p:ps) = liftM to . mapP' (mapP f ps) p . from + +-- | Version of |mapP| for trees with references +mapPR :: (Transform a, Monad m) => + (Fix (WithRef a) -> m (Fix (WithRef a))) + -> Path a -> Fix (WithRef a) -> m (Fix (WithRef a)) +mapPR f p (In (Ref _)) = fail "mapPR" +mapPR f [] x = f x +mapPR f (p:ps) (In (InR r)) = mapP' (mapPR f ps) p r >>= return . In . InR + +class MapP f where + mapP' :: Monad m => (b -> m b) -> Dir f -> f b -> m (f b) + +instance MapP I where + mapP' f CId (I r) = liftM I (f r) + +instance MapP (K a) where + mapP' _ _ (K x) = liftM K (return x) + +instance MapP U where + mapP' _ _ U = return U + +instance (MapP f, MapP g) => MapP (f :+: g) where + mapP' f (CL p) (L x) = liftM L (mapP' f p x) + mapP' f (CR p) (R x) = liftM R (mapP' f p x) + +instance (MapP f, MapP g) => MapP (f :*: g) where + mapP' f (C1 p _) (x :*: y) = liftM2 (:*:) (mapP' f p x) (return y) + mapP' f (C2 _ p) (x :*: y) = liftM2 (:*:) (return x) (mapP' f p y) + +instance MapP f => MapP (C c f) where + mapP' f (CC p) (C x) = liftM C (mapP' f p x) + +instance MapP f => MapP (S s f) where + mapP' f (CS p) (S x) = liftM S (mapP' f p x) + +-------------------------------------------------------------------------------- +-- Children +-------------------------------------------------------------------------------- +-- | Get the immediate children +imChildren :: (Regular a, Children (PF a)) => a -> [a] +imChildren = map fst . children . from + +-- | Get all children with their paths +childrenPaths :: (Regular a, Children (PF a)) => a -> [(a,Path a)] +childrenPaths a = (a,[]) : [ (r, n : p) + | (c, n) <- children (from a) + , (r, p) <- childrenPaths c ] + +class Children f where + children :: f a -> [(a, Dir f)] + +instance Children I where + children (I r) = [(r, CId)] + +instance Children (K a) where + children (K _) = [] + +instance Children U where + children U = [] + +instance (Children f, Children g) => Children (f :+: g) where + children (L x) = [ (a, CL p) | (a,p) <- children x ] + children (R x) = [ (a, CR p) | (a,p) <- children x ] + +instance (Children f, Children g) => Children (f :*: g) where + children (x :*: y) = [ (a, C1 p nullY) | (a,p) <- children x ] + ++ [ (a, C2 nullX p) | (a,p) <- children y ] + where nullX = error "nullX" -- fmap (const ()) x + nullY = error "nullY" -- fmap (const ()) y +-- The errors above should be safe, because we're never inspecting those anyway + +instance Children f => Children (C c f) where + children (C x) = [ (a, CC p) | (a,p) <- children x ] + +instance Children f => Children (S s f) where + children (S x) = [ (a, CS p) | (a,p) <- children x ] + +-------------------------------------------------------------------------------- +-- ZipChildren +-------------------------------------------------------------------------------- +zipChildrenM :: (Transform a, Monad m) => (Path a -> a -> a -> m b) -> a -> a -> m [b] +zipChildrenM f a b = zipChildren f (:[]) (from a) (from b) + +class ZipChildren f where + zipChildren :: Monad m => (Path a -> a -> a -> m b) -> (Dir f -> Path a) -> f a -> f a -> m [b] + +instance ZipChildren I where + zipChildren f p (I a) (I b) = f (p CId) a b >>= \x -> return [x] + +instance ZipChildren (K a) where + zipChildren _ _ _ _ = return [] + +instance ZipChildren U where + zipChildren _ _ _ _ = return [] + +instance (ZipChildren f, ZipChildren g) => ZipChildren (f :+: g) where + zipChildren f p (L x) (L y) = zipChildren f (p . CL) x y + zipChildren f p (R x) (R y) = zipChildren f (p . CR) x y + +instance (ZipChildren f, ZipChildren g) => ZipChildren (f :*: g) where + zipChildren f p (x1 :*: y1) (x2 :*: y2) = + liftM2 (++) (zipChildren f (\x -> p $ C1 x nullY) x1 x2) + (zipChildren f (\x -> p $ C2 nullX x) y1 y2) + where nullX = error "nullX" -- fmap (const ()) x + nullY = error "nullY" -- fmap (const ()) y +-- The errors above should be safe, because we're never inspecting those anyway + +instance ZipChildren f => ZipChildren (C c f) where + zipChildren f p (C x) (C y) = zipChildren f (p . CC) x y + +instance ZipChildren f => ZipChildren (S s f) where + zipChildren f p (S x) (S y) = zipChildren f (p . CS) x y + +-------------------------------------------------------------------------------- +-- Nicer interface +-------------------------------------------------------------------------------- +class HasRef a where + type RefRep a + + toRef :: WithRef a (RefRep a) -> RefRep a + fromRef :: RefRep a -> WithRef a (RefRep a) + +type NiceTransformation a = [ (Path a, RefRep a) ] + +toNiceTransformation :: (Functor (PF a), HasRef a) + => Transformation a -> NiceTransformation a +toNiceTransformation = map (\(p,e) -> (p, tr e)) where + tr = toRef . fmap tr . out + +fromNiceTransformation :: (Functor (PF a), HasRef a) + => NiceTransformation a -> Transformation a +fromNiceTransformation = map (\(p,e) -> (p, fr e)) where + fr = In . fmap fr . fromRef
− Generics/Regular/Transformations/RewriteRules.hs
@@ -1,31 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE UndecidableInstances #-}-{-# LANGUAGE ScopedTypeVariables #-}--module Generics.Regular.Transformations.RewriteRules (- Transform, Transformation, apply- ) where--import Generics.Regular-import Generics.Regular.Rewriting-import Generics.Regular.Zipper--import Control.Monad ( foldM )------------------------------------------------------------------------------------- Patch------------------------------------------------------------------------------------ Basically, a class synonym-class (Regular a, Rewrite a, Zipper (PF a)) => Transform a-instance Transform a => Rewrite a---- An edit is a list of:-type Transformation a = [ ( Loc a -> Maybe (Loc a) -- A path to the location to edit- , Rule a) ] -- The rewrite rule to apply there---- Patching is terribly simple: at the given locations, apply all the rules,--- then exit the zipper.-apply :: forall a. (Transform a) => Transformation a -> a -> Maybe a-apply rs = fmap leave . flip (foldM appRule) rs . enter- where appRule a (l,r) = l a >>= updateM (rewriteM r)
− Generics/Regular/Transformations/TH.hs
@@ -1,191 +0,0 @@-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE UndecidableInstances #-}--module Generics.Regular.Transformations.TH ( - deriveRefRep, prefix, postfix- ) where--import Generics.Regular-import Language.Haskell.TH-import Generics.Regular.Transformations.Explicit---- Code taken from regular library and adapted to work with transformations---- | Derive data type with references and 'HasRef' instance. For a data type--- N the name of the constructor for a reference is RefN, and the given--- function is used to change the rest of the constructors and the data--- type name itself. For example, for the following definition:------ > data Tree = Leaf Int | Bin Tree Tree--- > $(deriveRefRep ''Tree (postfix "R"))------ The following data type is generated:------ > data TreeR = LeafR Int | BinR TreeR TreeR | RefTree Path--- > instance HasRef Tree-deriveRefRep :: Name -> (Name -> Name) -> Q [Dec]-deriveRefRep t namef = do- d <- deriveData t namef- ins <- deriveInst t namef- return [d,ins]--deriveData :: Name -> (Name -> Name) -> Q Dec-deriveData t namef = do- let nm = namef t- i <- reify t- cons <- case i of- TyConI (DataD _ _ _ cs _) -> mapM (mkCon t namef nm) cs- r <- normalC (prefix "Ref" t) [return (NotStrict, ConT ''Path)]- dataD (cxt []) nm (typeVariables i) (map return $ r : cons) []--mkCon :: Name -> (Name -> Name) -> Name -> Con -> Q Con-mkCon t namef repname (NormalC a b) = normalC (namef a) (map f b) where- f :: (Strict, Type) -> Q (Strict, Type)- f (s,t') | t' == ConT t = return (s, ConT repname)- | otherwise = return (s, t')--prefix :: String -> Name -> Name-prefix pref n = mkName $ pref ++ nameBase n--postfix :: String -> Name -> Name-postfix post n = mkName $ nameBase n ++ post--deriveInst :: Name -> (Name -> Name) -> Q Dec-deriveInst t namef =- do- i <- reify t- let typ = foldl (\a -> AppT a . VarT . tyVarBndrToName) (ConT t) (typeVariables i)- let rn = prefix "Ref" t- fcs <- mkFrom t 1 0 namef rn t- tcs <- mkTo t 1 0 namef rn t- let typ' = return $ foldl (\a -> AppT a . VarT . tyVarBndrToName) (ConT $ namef t) (typeVariables i) - instanceD (cxt []) (conT ''HasRef `appT` return typ)- [tySynInstD ''RefRep [return typ] typ', funD 'toRef tcs, funD 'fromRef fcs]--lrE :: Int -> Int -> (Q Exp -> Q Exp)-lrE 1 0 e = e-lrE m 0 e = conE 'L `appE` e-lrE m i e = conE 'R `appE` lrE (m-1) (i-1) e--tyVarBndrToName :: TyVarBndr -> Name-tyVarBndrToName (PlainTV name) = name-tyVarBndrToName (KindedTV name _) = name--typeVariables :: Info -> [TyVarBndr]-typeVariables (TyConI (DataD _ _ tv _ _)) = tv-typeVariables (TyConI (NewtypeD _ _ tv _ _)) = tv-typeVariables _ = []--mkFrom :: Name -> Int -> Int -> (Name -> Name) -> Name -> Name -> Q [Q Clause]-mkFrom ns m i namef refname n = do- let wrapE e = conE 'InR `appE` lrE m i e- i <- reify n- let r = clause [conP refname [varP $ field 0]] (normalB $ conE 'Ref `appE` varE (field 0)) []- let b = case i of- TyConI (DataD _ dt vs cs _) ->- zipWith (fromCon wrapE ns namef (dt, map tyVarBndrToName vs) (length cs)) [0..] cs- TyConI (NewtypeD _ dt vs c _) ->- [fromCon wrapE ns namef (dt, map tyVarBndrToName vs) 1 0 c]- TyConI (TySynD t _ _) ->- [clause [varP (field 0)] (normalB (wrapE $ conE 'K `appE` varE (field 0))) []]- _ -> error "unknown construct"- return $ r : b--mkTo :: Name -> Int -> Int -> (Name -> Name) -> Name -> Name -> Q [Q Clause]-mkTo ns m i namef refname n = do- let wrapP p = conP 'InR [lrP m i p]- i <- reify n- let r = clause [conP 'Ref [varP $ field 0]] (normalB $ conE refname `appE` varE (field 0)) []- let b = case i of- TyConI (DataD _ dt vs cs _) ->- zipWith (toCon wrapP ns namef (dt, map tyVarBndrToName vs) (length cs)) [0..] cs- TyConI (NewtypeD _ dt vs c _) ->- [toCon wrapP ns namef (dt, map tyVarBndrToName vs) 1 0 c]- TyConI (TySynD t _ _) ->- [clause [wrapP $ conP 'K [varP (field 0)]] (normalB $ varE (field 0)) []]- _ -> error "unknown construct" - return $ r : b--fromCon :: (Q Exp -> Q Exp) -> Name -> (Name -> Name) -> (Name, [Name]) -> Int -> Int -> Con -> Q Clause-fromCon wrap ns namef (dt, vs) m i (NormalC cn []) =- clause- [conP (namef cn) []]- (normalB $ wrap $ lrE m i $ conE 'C `appE` (conE 'U)) []-fromCon wrap ns namef (dt, vs) m i (NormalC cn fs) =- clause- [conP (namef cn) (map (varP . field) [0..length fs - 1])]- (normalB $ wrap $ lrE m i $ conE 'C `appE` foldr1 prod (zipWith (fromField (dt, vs)) [0..] (map snd fs))) []- where- prod x y = conE '(:*:) `appE` x `appE` y-fromCon wrap ns namef (dt, vs) m i r@(RecC cn []) =- clause- [conP (namef cn) []]- (normalB $ wrap $ lrE m i $ conE 'C `appE` (conE 'U)) []-fromCon wrap ns namef (dt, vs) m i r@(RecC cn fs) =- clause- [conP (namef cn) (map (varP . field) [0..length fs - 1])]- (normalB $ wrap $ lrE m i $ conE 'C `appE` foldr1 prod (zipWith (fromField' (dt, vs)) [0..] fs)) []- where- prod x y = conE '(:*:) `appE` x `appE` y-fromCon wrap ns namef (dt, vs) m i (InfixC t1 cn t2) =- fromCon wrap ns namef (dt, vs) m i (NormalC cn [t1,t2])--fromField :: (Name, [Name]) -> Int -> Type -> Q Exp-fromField (dt, vs) nr t | t == dataDeclToType (dt, vs) = - conE 'I `appE` varE (field nr)-fromField (dt, vs) nr t = - conE 'K `appE` varE (field nr)--fromField' :: (Name, [Name]) -> Int -> (Name, Strict, Type) -> Q Exp-fromField' (dt, vs) nr (_, _, t) | t == dataDeclToType (dt, vs) =- conE 'S `appE` (conE 'I `appE` varE (field nr))-fromField' (dt, vs) nr (_, _, t) =- conE 'S `appE` (conE 'K `appE` varE (field nr))--toCon :: (Q Pat -> Q Pat) -> Name -> (Name -> Name) -> (Name, [Name]) -> Int -> Int -> Con -> Q Clause-toCon wrap ns namef (dt, vs) m i (NormalC cn []) =- clause- [wrap $ lrP m i $ conP 'C [conP 'U []]]- (normalB $ conE $ namef cn) []-toCon wrap ns namef (dt, vs) m i (NormalC cn fs) =- -- runIO (putStrLn ("constructor " ++ show ix)) >>- clause- [wrap $ lrP m i $ conP 'C [foldr1 prod (zipWith (toField (dt, vs)) [0..] (map snd fs))]]- (normalB $ foldl appE (conE $ namef cn) (map (varE . field) [0..length fs - 1])) []- where- prod x y = conP '(:*:) [x,y]-toCon wrap ns namef (dt, vs) m i r@(RecC cn []) =- clause- [wrap $ lrP m i $ conP 'C [conP 'U []]]- (normalB $ conE $ namef cn) []-toCon wrap ns namef (dt, vs) m i r@(RecC cn fs) =- clause- [wrap $ lrP m i $ conP 'C [foldr1 prod (zipWith (toField' (dt, vs)) [0..] fs)]]- (normalB $ foldl appE (conE $ namef cn) (map (varE . field) [0..length fs - 1])) []- where- prod x y = conP '(:*:) [x,y]-toCon wrap ns namef (dt, vs) m i (InfixC t1 cn t2) =- toCon wrap ns namef (dt, vs) m i (NormalC cn [t1,t2])--toField :: (Name, [Name]) -> Int -> Type -> Q Pat-toField (dt, vs) nr t | t == dataDeclToType (dt, vs) = - conP 'I [varP (field nr)]-toField (dt, vs) nr t = - conP 'K [varP (field nr)]--toField' :: (Name, [Name]) -> Int -> (Name, Strict, Type) -> Q Pat-toField' (dt, vs) nr (_, _, t) | t == dataDeclToType (dt, vs) = conP 'S [conP 'I [varP (field nr)]]-toField' (dt, vs) nr (_, _, t) = conP 'S [conP 'K [varP (field nr)]]--field :: Int -> Name-field n = mkName $ "f" ++ show n--lrP :: Int -> Int -> (Q Pat -> Q Pat)-lrP 1 0 p = p-lrP m 0 p = conP 'L [p]-lrP m i p = conP 'R [lrP (m-1) (i-1) p]--dataDeclToType :: (Name, [Name]) -> Type-dataDeclToType (dt, vs) = foldl (\a b -> AppT a (VarT b)) (ConT dt) vs
− Generics/Regular/Transformations/ZipperState.hs
@@ -1,57 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}--module Generics.Regular.Transformations.ZipperState (- ZipperMonad, ZipperState, upMonad, downMonad, leftMonad, rightMonad, - navigate, saveMonad, loadMonad, topMonad, updateMonad- ) where--import Control.Monad.State (StateT (..), evalStateT, get, put)--import Generics.Regular.Zipper-import Generics.Regular ( Regular, PF )------------------------------------------------------------------------------------- A zipper with state-----------------------------------------------------------------------------------type ZipperState a = ([a], Loc a)-type ZipperMonad a b = StateT (ZipperState a) Maybe b--moveMonad :: (Loc a -> Maybe (Loc a)) -> ZipperMonad a a-moveMonad m = StateT (\(s,l) -> m l >>= (\l' -> return (on l', (s,l'))))--upMonad, downMonad, leftMonad, rightMonad :: ZipperMonad a a-upMonad = moveMonad up-downMonad = moveMonad down-leftMonad = moveMonad left-rightMonad = moveMonad right--updateMonad :: (a -> a) -> ZipperMonad a a-updateMonad f = do (s,l) <- get- let l' = update f l- put (s,l')- return (on l')--saveMonad :: ZipperMonad a a-saveMonad = do (s,l) <- get- let a = on l- put (s++[a],l)- return a--loadMonad :: ZipperMonad a a-loadMonad = do (s:ss,l) <- get- let l' = update (const s) l- put (ss,l')- return (on l')--topMonad :: ZipperMonad a a-topMonad = do (_, Loc x l) <- get- case l of- [] -> return x- _ -> upMonad >> topMonad--leaveMonad :: Loc a -> ZipperMonad a b -> Maybe a-leaveMonad s m = evalStateT (m >> topMonad) ([],s)--navigate :: (Regular a, Zipper (PF a)) => a -> ZipperMonad a b -> Maybe a-navigate x m = leaveMonad (enter x) m
Generics/Regular/Zipper.hs view
@@ -1,245 +1,244 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE TupleSections #-}--module Generics.Regular.Zipper- (-- * Locations- Loc(..),- -- * Context frames- Ctx(),- -- * Generic zipper class- Zipper(..),- -- * Interface- enter,- down, down', up, right, left,- -- dfnext, dfprev,- leave, on, update, updateM-- )- where--import Prelude hiding (last)--import Control.Monad-import Control.Monad.State-import Control.Applicative-import Data.Maybe-import Data.Traversable--import Generics.Regular hiding (left, right)---- * Locations and context stacks---- | Abstract type of locations. A location contains the current focus--- and its context. A location is parameterized over the family of--- datatypes and over the type of the complete value.--data Loc :: * -> * where- Loc :: (Regular a, Zipper (PF a)) => a -> [Ctx (PF a) a] -> Loc a---- * Context frames---- | Abstract type of context frames. Not required for the high-level--- navigation functions.--data family Ctx (f :: * -> *) :: * -> *--data instance Ctx (K a) r-data instance Ctx U r-data instance Ctx (f :+: g) r = CL (Ctx f r) | CR (Ctx g r)-data instance Ctx (f :*: g) r = C1 (Ctx f r) (g r) | C2 (f r) (Ctx g r)-data instance Ctx I r = CId-data instance Ctx (C c f) r = CC (Ctx f r)-data instance Ctx (S s f) r = CS (Ctx f r)---- * Contexts and locations are functors--instance Zipper f => Functor (Ctx f) where- fmap = cmap---- instance Functor (Loc f) where- -- fmap f (Loc p x) = Loc (f p) (map (fmap f) x)---- * Generic navigation functions---- | It is in general not necessary to use the generic navigation--- functions directly. The functions listed in the ``Interface'' section--- below are more user-friendly.-----class Functor f => Zipper f where- cmap :: (a -> b) -> Ctx f a -> Ctx f b- fill :: Ctx f a -> a -> f a- first, last :: f a -> Maybe (a, Ctx f a)- next, prev :: Ctx f a -> a -> Maybe (a, Ctx f a)--instance Zipper I where- cmap f CId = CId- fill CId x = I x- first (I x) = Just (x, CId)- last (I x) = Just (x, CId)- next CId x = Nothing- prev CId x = Nothing--instance Zipper (K a) where- cmap f void = impossible void- fill void x = impossible void- first (K a) = Nothing- last (K a) = Nothing- next void x = impossible void- prev void x = impossible void--instance Zipper U where- cmap f void = impossible void- fill void x = impossible void- first U = Nothing- last U = Nothing- next void x = impossible void- prev void x = impossible void--instance (Zipper f, Zipper g) => Zipper (f :+: g) where- cmap f (CL c) = CL (cmap f c)- cmap f (CR c) = CR (cmap f c)- fill (CL c) x = L (fill c x)- fill (CR c) y = R (fill c y)- first (L x) = first x >>= return . fmap CL- first (R x) = first x >>= return . fmap CR- last (L x) = last x >>= return . fmap CL- last (R x) = last x >>= return . fmap CR- next (CL c) x = next c x >>= return . fmap CL- next (CR c) x = next c x >>= return . fmap CR- prev (CL c) x = prev c x >>= return . fmap CL- prev (CR c) x = prev c x >>= return . fmap CR--instance (Zipper f, Zipper g) => Zipper (f :*: g) where- cmap f (C1 c y) = C1 (cmap f c) (fmap f y)- cmap f (C2 x c) = C2 (fmap f x) (cmap f c)- fill (C1 c y) x = fill c x :*: y- fill (C2 x c) y = x :*: fill c y- first (x :*: y) = fmap (fmap (flip C1 y)) (first x)- `mplus` fmap (fmap (C2 x)) (first y)- last (x :*: y) = fmap (fmap (C2 x)) (last y)- `mplus` fmap (fmap (flip C1 y)) (last x)- next (C1 c y) z = (fmap (flip C1 y) <$> next c z)- `mplus` (fmap (C2 (fill c z)) <$> first y)- next (C2 x c) z = fmap (C2 x) <$> next c z- prev (C1 c y) z = fmap (flip C1 y) <$> prev c z- prev (C2 x c) z = (fmap (C2 x) <$> prev c z)- `mplus` (fmap (flip C1 (fill c z)) <$> last x)--instance (Zipper f) => Zipper (C c f) where- cmap f (CC c) = CC (cmap f c)- fill (CC c) x = C (fill c x)- first (C x) = first x >>= return . fmap CC- last (C x) = last x >>= return . fmap CC- next (CC c) x = next c x >>= return . fmap CC- prev (CC c) x = prev c x >>= return . fmap CC--instance (Zipper f) => Zipper (S s f) where- cmap f (CS c) = CS (cmap f c)- fill (CS c) x = S (fill c x)- first (S x) = first x >>= return . fmap CS- last (S x) = last x >>= return . fmap CS- next (CS c) x = next c x >>= return . fmap CS- prev (CS c) x = prev c x >>= return . fmap CS---- * Interface---- ** Introduction---- | Start navigating a datastructure. Returns a location that--- focuses the entire value and has an empty context.-enter :: (Regular a, Zipper (PF a)) => a -> Loc a-enter x = Loc x []---- ** Navigation---- | Move down to the leftmost child. Returns 'Nothing' if the--- current focus is a leaf.-down :: Loc a -> Maybe (Loc a)-down (Loc x cs) = first (from x) >>= \(a,c) -> return (Loc a (c:cs))---- | Move down to the rightmost child. Returns 'Nothing' if the--- current focus is a leaf.-down' :: Loc a -> Maybe (Loc a)-down' (Loc x cs) = last (from x) >>= \(a,c) -> return (Loc a (c:cs))---- | Move up to the parent. Returns 'Nothing' if the current--- focus is the root.-up :: Loc a -> Maybe (Loc a)-up (Loc x []) = Nothing-up (Loc x (c:cs)) = return (Loc (to (fill c x)) cs)---- | Move to the right sibling. Returns 'Nothing' if the current--- focus is the rightmost sibling.-right :: Loc a -> Maybe (Loc a)-right (Loc x [] ) = Nothing-right (Loc x (c:cs)) = next c x >>= \(a,c') -> return (Loc a (c':cs))---- | Move to the left sibling. Returns 'Nothing' if the current--- focus is the leftmost sibling.-left :: Loc a -> Maybe (Loc a)-left (Loc x [] ) = Nothing-left (Loc x (c:cs)) = prev c x >>= \(a,c') -> return (Loc a (c':cs))----- ** Derived navigation.-{--df :: (a -> Maybe a) -> (a -> Maybe a) -> (a -> Maybe a) -> a -> Maybe a-df d u lr l =- case d l of- Nothing -> df' l- r -> r- where- df' l =- case lr l of- Nothing -> case u l of- Nothing -> Nothing- Just l' -> df' l'- r -> r---- | Move through all positions in depth-first left-to-right order.-dfnext :: Loc phi I0 ix -> Maybe (Loc phi I0 ix)-dfnext = df down up right---- | Move through all positions in depth-first right-to-left order.-dfprev :: Loc phi I0 ix -> Maybe (Loc phi I0 ix)-dfprev = df down' up left--}---- | Utility--- navigate :: (Regular a, Zipper (PF a))- -- => a -> (Loc a -> Maybe (Loc a)) -> Loc a--- navigate a f = fromJust $ f (enter a)---- ** Elimination---- | Return the entire value, independent of the current focus.-leave :: Loc a -> a-leave (Loc x []) = x-leave loc = leave (fromJust (up loc))---- | Operate on the current focus. This function can be used to--- extract the current point of focus.-on :: Loc a -> a-on (Loc x _) = x---- | Update the current focus without changing its type.-update :: (a -> a) -> Loc a -> Loc a-update f (Loc x cs) = Loc (f x) cs---- | Update the current focus without changing its type.-updateM :: Monad m => (a -> m a) -> Loc a -> m (Loc a)-updateM f (Loc x cs) = f x >>= \y -> return (Loc y cs)---- * Internal functions--impossible :: a -> b-impossible x = x `seq` error "impossible"+{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE EmptyDataDecls #-} +{-# LANGUAGE TupleSections #-} + +module Generics.Regular.Zipper + (-- * Locations + Loc(..), + -- * Context frames + Ctx(..), + -- * Generic zipper class + Zipper(..), + -- * Interface + enter, + down, down', up, right, left, + -- dfnext, dfprev, + leave, on, update, updateM + + ) + where + +import Prelude hiding (last) + +import Control.Monad +import Control.Monad.State +import Control.Applicative +import Data.Maybe + +import Generics.Regular hiding (left, right) + +-- * Locations and context stacks + +-- | Abstract type of locations. A location contains the current focus +-- and its context. A location is parameterized over the family of +-- datatypes and over the type of the complete value. + +data Loc :: * -> * where + Loc :: (Regular a, Zipper (PF a)) => a -> [Ctx (PF a) a] -> Loc a + +-- * Context frames + +-- | Abstract type of context frames. Not required for the high-level +-- navigation functions. + +data family Ctx (f :: * -> *) :: * -> * + +data instance Ctx (K a) r +data instance Ctx U r +data instance Ctx (f :+: g) r = CL (Ctx f r) | CR (Ctx g r) +data instance Ctx (f :*: g) r = C1 (Ctx f r) (g r) | C2 (f r) (Ctx g r) +data instance Ctx I r = CId +data instance Ctx (C c f) r = CC (Ctx f r) +data instance Ctx (S s f) r = CS (Ctx f r) + +-- * Contexts and locations are functors + +instance Zipper f => Functor (Ctx f) where + fmap = cmap + +-- instance Functor (Loc f) where + -- fmap f (Loc p x) = Loc (f p) (map (fmap f) x) + +-- * Generic navigation functions + +-- | It is in general not necessary to use the generic navigation +-- functions directly. The functions listed in the ``Interface'' section +-- below are more user-friendly. +-- + +class Functor f => Zipper f where + cmap :: (a -> b) -> Ctx f a -> Ctx f b + fill :: Ctx f a -> a -> f a + first, last :: f a -> Maybe (a, Ctx f a) + next, prev :: Ctx f a -> a -> Maybe (a, Ctx f a) + +instance Zipper I where + cmap f CId = CId + fill CId x = I x + first (I x) = Just (x, CId) + last (I x) = Just (x, CId) + next CId x = Nothing + prev CId x = Nothing + +instance Zipper (K a) where + cmap f void = impossible void + fill void x = impossible void + first (K a) = Nothing + last (K a) = Nothing + next void x = impossible void + prev void x = impossible void + +instance Zipper U where + cmap f void = impossible void + fill void x = impossible void + first U = Nothing + last U = Nothing + next void x = impossible void + prev void x = impossible void + +instance (Zipper f, Zipper g) => Zipper (f :+: g) where + cmap f (CL c) = CL (cmap f c) + cmap f (CR c) = CR (cmap f c) + fill (CL c) x = L (fill c x) + fill (CR c) y = R (fill c y) + first (L x) = first x >>= return . fmap CL + first (R x) = first x >>= return . fmap CR + last (L x) = last x >>= return . fmap CL + last (R x) = last x >>= return . fmap CR + next (CL c) x = next c x >>= return . fmap CL + next (CR c) x = next c x >>= return . fmap CR + prev (CL c) x = prev c x >>= return . fmap CL + prev (CR c) x = prev c x >>= return . fmap CR + +instance (Zipper f, Zipper g) => Zipper (f :*: g) where + cmap f (C1 c y) = C1 (cmap f c) (fmap f y) + cmap f (C2 x c) = C2 (fmap f x) (cmap f c) + fill (C1 c y) x = fill c x :*: y + fill (C2 x c) y = x :*: fill c y + first (x :*: y) = fmap (fmap (flip C1 y)) (first x) + `mplus` fmap (fmap (C2 x)) (first y) + last (x :*: y) = fmap (fmap (C2 x)) (last y) + `mplus` fmap (fmap (flip C1 y)) (last x) + next (C1 c y) z = (fmap (flip C1 y) <$> next c z) + `mplus` (fmap (C2 (fill c z)) <$> first y) + next (C2 x c) z = fmap (C2 x) <$> next c z + prev (C1 c y) z = fmap (flip C1 y) <$> prev c z + prev (C2 x c) z = (fmap (C2 x) <$> prev c z) + `mplus` (fmap (flip C1 (fill c z)) <$> last x) + +instance (Zipper f) => Zipper (C c f) where + cmap f (CC c) = CC (cmap f c) + fill (CC c) x = C (fill c x) + first (C x) = first x >>= return . fmap CC + last (C x) = last x >>= return . fmap CC + next (CC c) x = next c x >>= return . fmap CC + prev (CC c) x = prev c x >>= return . fmap CC + +instance (Zipper f) => Zipper (S s f) where + cmap f (CS c) = CS (cmap f c) + fill (CS c) x = S (fill c x) + first (S x) = first x >>= return . fmap CS + last (S x) = last x >>= return . fmap CS + next (CS c) x = next c x >>= return . fmap CS + prev (CS c) x = prev c x >>= return . fmap CS + +-- * Interface + +-- ** Introduction + +-- | Start navigating a datastructure. Returns a location that +-- focuses the entire value and has an empty context. +enter :: (Regular a, Zipper (PF a)) => a -> Loc a +enter x = Loc x [] + +-- ** Navigation + +-- | Move down to the leftmost child. Returns 'Nothing' if the +-- current focus is a leaf. +down :: Loc a -> Maybe (Loc a) +down (Loc x cs) = first (from x) >>= \(a,c) -> return (Loc a (c:cs)) + +-- | Move down to the rightmost child. Returns 'Nothing' if the +-- current focus is a leaf. +down' :: Loc a -> Maybe (Loc a) +down' (Loc x cs) = last (from x) >>= \(a,c) -> return (Loc a (c:cs)) + +-- | Move up to the parent. Returns 'Nothing' if the current +-- focus is the root. +up :: Loc a -> Maybe (Loc a) +up (Loc x []) = Nothing +up (Loc x (c:cs)) = return (Loc (to (fill c x)) cs) + +-- | Move to the right sibling. Returns 'Nothing' if the current +-- focus is the rightmost sibling. +right :: Loc a -> Maybe (Loc a) +right (Loc x [] ) = Nothing +right (Loc x (c:cs)) = next c x >>= \(a,c') -> return (Loc a (c':cs)) + +-- | Move to the left sibling. Returns 'Nothing' if the current +-- focus is the leftmost sibling. +left :: Loc a -> Maybe (Loc a) +left (Loc x [] ) = Nothing +left (Loc x (c:cs)) = prev c x >>= \(a,c') -> return (Loc a (c':cs)) + + +-- ** Derived navigation. +{- +df :: (a -> Maybe a) -> (a -> Maybe a) -> (a -> Maybe a) -> a -> Maybe a +df d u lr l = + case d l of + Nothing -> df' l + r -> r + where + df' l = + case lr l of + Nothing -> case u l of + Nothing -> Nothing + Just l' -> df' l' + r -> r + +-- | Move through all positions in depth-first left-to-right order. +dfnext :: Loc phi I0 ix -> Maybe (Loc phi I0 ix) +dfnext = df down up right + +-- | Move through all positions in depth-first right-to-left order. +dfprev :: Loc phi I0 ix -> Maybe (Loc phi I0 ix) +dfprev = df down' up left +-} + +-- | Utility +-- navigate :: (Regular a, Zipper (PF a)) + -- => a -> (Loc a -> Maybe (Loc a)) -> Loc a +-- navigate a f = fromJust $ f (enter a) + +-- ** Elimination + +-- | Return the entire value, independent of the current focus. +leave :: Loc a -> a +leave (Loc x []) = x +leave loc = leave (fromJust (up loc)) + +-- | Operate on the current focus. This function can be used to +-- extract the current point of focus. +on :: Loc a -> a +on (Loc x _) = x + +-- | Update the current focus without changing its type. +update :: (a -> a) -> Loc a -> Loc a +update f (Loc x cs) = Loc (f x) cs + +-- | Update the current focus without changing its type. +updateM :: Monad m => (a -> m a) -> Loc a -> m (Loc a) +updateM f (Loc x cs) = f x >>= \y -> return (Loc y cs) + +-- * Internal functions + +impossible :: a -> b +impossible x = x `seq` error "impossible"
LICENSE view
@@ -1,675 +1,675 @@- GNU GENERAL PUBLIC LICENSE- Version 3, 29 June 2007-- Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>- Everyone is permitted to copy and distribute verbatim copies- of this license document, but changing it is not allowed.-- Preamble-- The GNU General Public License is a free, copyleft license for-software and other kinds of works.-- The licenses for most software and other practical works are designed-to take away your freedom to share and change the works. By contrast,-the GNU General Public License is intended to guarantee your freedom to-share and change all versions of a program--to make sure it remains free-software for all its users. We, the Free Software Foundation, use the-GNU General Public License for most of our software; it applies also to-any other work released this way by its authors. You can apply it to-your programs, too.-- When we speak of free software, we are referring to freedom, not-price. Our General Public Licenses are designed to make sure that you-have the freedom to distribute copies of free software (and charge for-them if you wish), that you receive source code or can get it if you-want it, that you can change the software or use pieces of it in new-free programs, and that you know you can do these things.-- To protect your rights, we need to prevent others from denying you-these rights or asking you to surrender the rights. Therefore, you have-certain responsibilities if you distribute copies of the software, or if-you modify it: responsibilities to respect the freedom of others.-- For example, if you distribute copies of such a program, whether-gratis or for a fee, you must pass on to the recipients the same-freedoms that you received. You must make sure that they, too, receive-or can get the source code. And you must show them these terms so they-know their rights.-- Developers that use the GNU GPL protect your rights with two steps:-(1) assert copyright on the software, and (2) offer you this License-giving you legal permission to copy, distribute and/or modify it.-- For the developers' and authors' protection, the GPL clearly explains-that there is no warranty for this free software. For both users' and-authors' sake, the GPL requires that modified versions be marked as-changed, so that their problems will not be attributed erroneously to-authors of previous versions.-- Some devices are designed to deny users access to install or run-modified versions of the software inside them, although the manufacturer-can do so. This is fundamentally incompatible with the aim of-protecting users' freedom to change the software. The systematic-pattern of such abuse occurs in the area of products for individuals to-use, which is precisely where it is most unacceptable. Therefore, we-have designed this version of the GPL to prohibit the practice for those-products. If such problems arise substantially in other domains, we-stand ready to extend this provision to those domains in future versions-of the GPL, as needed to protect the freedom of users.-- Finally, every program is threatened constantly by software patents.-States should not allow patents to restrict development and use of-software on general-purpose computers, but in those that do, we wish to-avoid the special danger that patents applied to a free program could-make it effectively proprietary. To prevent this, the GPL assures that-patents cannot be used to render the program non-free.-- The precise terms and conditions for copying, distribution and-modification follow.-- TERMS AND CONDITIONS-- 0. Definitions.-- "This License" refers to version 3 of the GNU General Public License.-- "Copyright" also means copyright-like laws that apply to other kinds of-works, such as semiconductor masks.- - "The Program" refers to any copyrightable work licensed under this-License. Each licensee is addressed as "you". "Licensees" and-"recipients" may be individuals or organizations.-- To "modify" a work means to copy from or adapt all or part of the work-in a fashion requiring copyright permission, other than the making of an-exact copy. The resulting work is called a "modified version" of the-earlier work or a work "based on" the earlier work.-- A "covered work" means either the unmodified Program or a work based-on the Program.-- To "propagate" a work means to do anything with it that, without-permission, would make you directly or secondarily liable for-infringement under applicable copyright law, except executing it on a-computer or modifying a private copy. Propagation includes copying,-distribution (with or without modification), making available to the-public, and in some countries other activities as well.-- To "convey" a work means any kind of propagation that enables other-parties to make or receive copies. Mere interaction with a user through-a computer network, with no transfer of a copy, is not conveying.-- An interactive user interface displays "Appropriate Legal Notices"-to the extent that it includes a convenient and prominently visible-feature that (1) displays an appropriate copyright notice, and (2)-tells the user that there is no warranty for the work (except to the-extent that warranties are provided), that licensees may convey the-work under this License, and how to view a copy of this License. If-the interface presents a list of user commands or options, such as a-menu, a prominent item in the list meets this criterion.-- 1. Source Code.-- The "source code" for a work means the preferred form of the work-for making modifications to it. "Object code" means any non-source-form of a work.-- A "Standard Interface" means an interface that either is an official-standard defined by a recognized standards body, or, in the case of-interfaces specified for a particular programming language, one that-is widely used among developers working in that language.-- The "System Libraries" of an executable work include anything, other-than the work as a whole, that (a) is included in the normal form of-packaging a Major Component, but which is not part of that Major-Component, and (b) serves only to enable use of the work with that-Major Component, or to implement a Standard Interface for which an-implementation is available to the public in source code form. A-"Major Component", in this context, means a major essential component-(kernel, window system, and so on) of the specific operating system-(if any) on which the executable work runs, or a compiler used to-produce the work, or an object code interpreter used to run it.-- The "Corresponding Source" for a work in object code form means all-the source code needed to generate, install, and (for an executable-work) run the object code and to modify the work, including scripts to-control those activities. However, it does not include the work's-System Libraries, or general-purpose tools or generally available free-programs which are used unmodified in performing those activities but-which are not part of the work. For example, Corresponding Source-includes interface definition files associated with source files for-the work, and the source code for shared libraries and dynamically-linked subprograms that the work is specifically designed to require,-such as by intimate data communication or control flow between those-subprograms and other parts of the work.-- The Corresponding Source need not include anything that users-can regenerate automatically from other parts of the Corresponding-Source.-- The Corresponding Source for a work in source code form is that-same work.-- 2. Basic Permissions.-- All rights granted under this License are granted for the term of-copyright on the Program, and are irrevocable provided the stated-conditions are met. This License explicitly affirms your unlimited-permission to run the unmodified Program. The output from running a-covered work is covered by this License only if the output, given its-content, constitutes a covered work. This License acknowledges your-rights of fair use or other equivalent, as provided by copyright law.-- You may make, run and propagate covered works that you do not-convey, without conditions so long as your license otherwise remains-in force. You may convey covered works to others for the sole purpose-of having them make modifications exclusively for you, or provide you-with facilities for running those works, provided that you comply with-the terms of this License in conveying all material for which you do-not control copyright. Those thus making or running the covered works-for you must do so exclusively on your behalf, under your direction-and control, on terms that prohibit them from making any copies of-your copyrighted material outside their relationship with you.-- Conveying under any other circumstances is permitted solely under-the conditions stated below. Sublicensing is not allowed; section 10-makes it unnecessary.-- 3. Protecting Users' Legal Rights From Anti-Circumvention Law.-- No covered work shall be deemed part of an effective technological-measure under any applicable law fulfilling obligations under article-11 of the WIPO copyright treaty adopted on 20 December 1996, or-similar laws prohibiting or restricting circumvention of such-measures.-- When you convey a covered work, you waive any legal power to forbid-circumvention of technological measures to the extent such circumvention-is effected by exercising rights under this License with respect to-the covered work, and you disclaim any intention to limit operation or-modification of the work as a means of enforcing, against the work's-users, your or third parties' legal rights to forbid circumvention of-technological measures.-- 4. Conveying Verbatim Copies.-- You may convey verbatim copies of the Program's source code as you-receive it, in any medium, provided that you conspicuously and-appropriately publish on each copy an appropriate copyright notice;-keep intact all notices stating that this License and any-non-permissive terms added in accord with section 7 apply to the code;-keep intact all notices of the absence of any warranty; and give all-recipients a copy of this License along with the Program.-- You may charge any price or no price for each copy that you convey,-and you may offer support or warranty protection for a fee.-- 5. Conveying Modified Source Versions.-- You may convey a work based on the Program, or the modifications to-produce it from the Program, in the form of source code under the-terms of section 4, provided that you also meet all of these conditions:-- a) The work must carry prominent notices stating that you modified- it, and giving a relevant date.-- b) The work must carry prominent notices stating that it is- released under this License and any conditions added under section- 7. This requirement modifies the requirement in section 4 to- "keep intact all notices".-- c) You must license the entire work, as a whole, under this- License to anyone who comes into possession of a copy. This- License will therefore apply, along with any applicable section 7- additional terms, to the whole of the work, and all its parts,- regardless of how they are packaged. This License gives no- permission to license the work in any other way, but it does not- invalidate such permission if you have separately received it.-- d) If the work has interactive user interfaces, each must display- Appropriate Legal Notices; however, if the Program has interactive- interfaces that do not display Appropriate Legal Notices, your- work need not make them do so.-- A compilation of a covered work with other separate and independent-works, which are not by their nature extensions of the covered work,-and which are not combined with it such as to form a larger program,-in or on a volume of a storage or distribution medium, is called an-"aggregate" if the compilation and its resulting copyright are not-used to limit the access or legal rights of the compilation's users-beyond what the individual works permit. Inclusion of a covered work-in an aggregate does not cause this License to apply to the other-parts of the aggregate.-- 6. Conveying Non-Source Forms.-- You may convey a covered work in object code form under the terms-of sections 4 and 5, provided that you also convey the-machine-readable Corresponding Source under the terms of this License,-in one of these ways:-- a) Convey the object code in, or embodied in, a physical product- (including a physical distribution medium), accompanied by the- Corresponding Source fixed on a durable physical medium- customarily used for software interchange.-- b) Convey the object code in, or embodied in, a physical product- (including a physical distribution medium), accompanied by a- written offer, valid for at least three years and valid for as- long as you offer spare parts or customer support for that product- model, to give anyone who possesses the object code either (1) a- copy of the Corresponding Source for all the software in the- product that is covered by this License, on a durable physical- medium customarily used for software interchange, for a price no- more than your reasonable cost of physically performing this- conveying of source, or (2) access to copy the- Corresponding Source from a network server at no charge.-- c) Convey individual copies of the object code with a copy of the- written offer to provide the Corresponding Source. This- alternative is allowed only occasionally and noncommercially, and- only if you received the object code with such an offer, in accord- with subsection 6b.-- d) Convey the object code by offering access from a designated- place (gratis or for a charge), and offer equivalent access to the- Corresponding Source in the same way through the same place at no- further charge. You need not require recipients to copy the- Corresponding Source along with the object code. If the place to- copy the object code is a network server, the Corresponding Source- may be on a different server (operated by you or a third party)- that supports equivalent copying facilities, provided you maintain- clear directions next to the object code saying where to find the- Corresponding Source. Regardless of what server hosts the- Corresponding Source, you remain obligated to ensure that it is- available for as long as needed to satisfy these requirements.-- e) Convey the object code using peer-to-peer transmission, provided- you inform other peers where the object code and Corresponding- Source of the work are being offered to the general public at no- charge under subsection 6d.-- A separable portion of the object code, whose source code is excluded-from the Corresponding Source as a System Library, need not be-included in conveying the object code work.-- A "User Product" is either (1) a "consumer product", which means any-tangible personal property which is normally used for personal, family,-or household purposes, or (2) anything designed or sold for incorporation-into a dwelling. In determining whether a product is a consumer product,-doubtful cases shall be resolved in favor of coverage. For a particular-product received by a particular user, "normally used" refers to a-typical or common use of that class of product, regardless of the status-of the particular user or of the way in which the particular user-actually uses, or expects or is expected to use, the product. A product-is a consumer product regardless of whether the product has substantial-commercial, industrial or non-consumer uses, unless such uses represent-the only significant mode of use of the product.-- "Installation Information" for a User Product means any methods,-procedures, authorization keys, or other information required to install-and execute modified versions of a covered work in that User Product from-a modified version of its Corresponding Source. The information must-suffice to ensure that the continued functioning of the modified object-code is in no case prevented or interfered with solely because-modification has been made.-- If you convey an object code work under this section in, or with, or-specifically for use in, a User Product, and the conveying occurs as-part of a transaction in which the right of possession and use of the-User Product is transferred to the recipient in perpetuity or for a-fixed term (regardless of how the transaction is characterized), the-Corresponding Source conveyed under this section must be accompanied-by the Installation Information. But this requirement does not apply-if neither you nor any third party retains the ability to install-modified object code on the User Product (for example, the work has-been installed in ROM).-- The requirement to provide Installation Information does not include a-requirement to continue to provide support service, warranty, or updates-for a work that has been modified or installed by the recipient, or for-the User Product in which it has been modified or installed. Access to a-network may be denied when the modification itself materially and-adversely affects the operation of the network or violates the rules and-protocols for communication across the network.-- Corresponding Source conveyed, and Installation Information provided,-in accord with this section must be in a format that is publicly-documented (and with an implementation available to the public in-source code form), and must require no special password or key for-unpacking, reading or copying.-- 7. Additional Terms.-- "Additional permissions" are terms that supplement the terms of this-License by making exceptions from one or more of its conditions.-Additional permissions that are applicable to the entire Program shall-be treated as though they were included in this License, to the extent-that they are valid under applicable law. If additional permissions-apply only to part of the Program, that part may be used separately-under those permissions, but the entire Program remains governed by-this License without regard to the additional permissions.-- When you convey a copy of a covered work, you may at your option-remove any additional permissions from that copy, or from any part of-it. (Additional permissions may be written to require their own-removal in certain cases when you modify the work.) You may place-additional permissions on material, added by you to a covered work,-for which you have or can give appropriate copyright permission.-- Notwithstanding any other provision of this License, for material you-add to a covered work, you may (if authorized by the copyright holders of-that material) supplement the terms of this License with terms:-- a) Disclaiming warranty or limiting liability differently from the- terms of sections 15 and 16 of this License; or-- b) Requiring preservation of specified reasonable legal notices or- author attributions in that material or in the Appropriate Legal- Notices displayed by works containing it; or-- c) Prohibiting misrepresentation of the origin of that material, or- requiring that modified versions of such material be marked in- reasonable ways as different from the original version; or-- d) Limiting the use for publicity purposes of names of licensors or- authors of the material; or-- e) Declining to grant rights under trademark law for use of some- trade names, trademarks, or service marks; or-- f) Requiring indemnification of licensors and authors of that- material by anyone who conveys the material (or modified versions of- it) with contractual assumptions of liability to the recipient, for- any liability that these contractual assumptions directly impose on- those licensors and authors.-- All other non-permissive additional terms are considered "further-restrictions" within the meaning of section 10. If the Program as you-received it, or any part of it, contains a notice stating that it is-governed by this License along with a term that is a further-restriction, you may remove that term. If a license document contains-a further restriction but permits relicensing or conveying under this-License, you may add to a covered work material governed by the terms-of that license document, provided that the further restriction does-not survive such relicensing or conveying.-- If you add terms to a covered work in accord with this section, you-must place, in the relevant source files, a statement of the-additional terms that apply to those files, or a notice indicating-where to find the applicable terms.-- Additional terms, permissive or non-permissive, may be stated in the-form of a separately written license, or stated as exceptions;-the above requirements apply either way.-- 8. Termination.-- You may not propagate or modify a covered work except as expressly-provided under this License. Any attempt otherwise to propagate or-modify it is void, and will automatically terminate your rights under-this License (including any patent licenses granted under the third-paragraph of section 11).-- However, if you cease all violation of this License, then your-license from a particular copyright holder is reinstated (a)-provisionally, unless and until the copyright holder explicitly and-finally terminates your license, and (b) permanently, if the copyright-holder fails to notify you of the violation by some reasonable means-prior to 60 days after the cessation.-- Moreover, your license from a particular copyright holder is-reinstated permanently if the copyright holder notifies you of the-violation by some reasonable means, this is the first time you have-received notice of violation of this License (for any work) from that-copyright holder, and you cure the violation prior to 30 days after-your receipt of the notice.-- Termination of your rights under this section does not terminate the-licenses of parties who have received copies or rights from you under-this License. If your rights have been terminated and not permanently-reinstated, you do not qualify to receive new licenses for the same-material under section 10.-- 9. Acceptance Not Required for Having Copies.-- You are not required to accept this License in order to receive or-run a copy of the Program. Ancillary propagation of a covered work-occurring solely as a consequence of using peer-to-peer transmission-to receive a copy likewise does not require acceptance. However,-nothing other than this License grants you permission to propagate or-modify any covered work. These actions infringe copyright if you do-not accept this License. Therefore, by modifying or propagating a-covered work, you indicate your acceptance of this License to do so.-- 10. Automatic Licensing of Downstream Recipients.-- Each time you convey a covered work, the recipient automatically-receives a license from the original licensors, to run, modify and-propagate that work, subject to this License. You are not responsible-for enforcing compliance by third parties with this License.-- An "entity transaction" is a transaction transferring control of an-organization, or substantially all assets of one, or subdividing an-organization, or merging organizations. If propagation of a covered-work results from an entity transaction, each party to that-transaction who receives a copy of the work also receives whatever-licenses to the work the party's predecessor in interest had or could-give under the previous paragraph, plus a right to possession of the-Corresponding Source of the work from the predecessor in interest, if-the predecessor has it or can get it with reasonable efforts.-- You may not impose any further restrictions on the exercise of the-rights granted or affirmed under this License. For example, you may-not impose a license fee, royalty, or other charge for exercise of-rights granted under this License, and you may not initiate litigation-(including a cross-claim or counterclaim in a lawsuit) alleging that-any patent claim is infringed by making, using, selling, offering for-sale, or importing the Program or any portion of it.-- 11. Patents.-- A "contributor" is a copyright holder who authorizes use under this-License of the Program or a work on which the Program is based. The-work thus licensed is called the contributor's "contributor version".-- A contributor's "essential patent claims" are all patent claims-owned or controlled by the contributor, whether already acquired or-hereafter acquired, that would be infringed by some manner, permitted-by this License, of making, using, or selling its contributor version,-but do not include claims that would be infringed only as a-consequence of further modification of the contributor version. For-purposes of this definition, "control" includes the right to grant-patent sublicenses in a manner consistent with the requirements of-this License.-- Each contributor grants you a non-exclusive, worldwide, royalty-free-patent license under the contributor's essential patent claims, to-make, use, sell, offer for sale, import and otherwise run, modify and-propagate the contents of its contributor version.-- In the following three paragraphs, a "patent license" is any express-agreement or commitment, however denominated, not to enforce a patent-(such as an express permission to practice a patent or covenant not to-sue for patent infringement). To "grant" such a patent license to a-party means to make such an agreement or commitment not to enforce a-patent against the party.-- If you convey a covered work, knowingly relying on a patent license,-and the Corresponding Source of the work is not available for anyone-to copy, free of charge and under the terms of this License, through a-publicly available network server or other readily accessible means,-then you must either (1) cause the Corresponding Source to be so-available, or (2) arrange to deprive yourself of the benefit of the-patent license for this particular work, or (3) arrange, in a manner-consistent with the requirements of this License, to extend the patent-license to downstream recipients. "Knowingly relying" means you have-actual knowledge that, but for the patent license, your conveying the-covered work in a country, or your recipient's use of the covered work-in a country, would infringe one or more identifiable patents in that-country that you have reason to believe are valid.- - If, pursuant to or in connection with a single transaction or-arrangement, you convey, or propagate by procuring conveyance of, a-covered work, and grant a patent license to some of the parties-receiving the covered work authorizing them to use, propagate, modify-or convey a specific copy of the covered work, then the patent license-you grant is automatically extended to all recipients of the covered-work and works based on it.-- A patent license is "discriminatory" if it does not include within-the scope of its coverage, prohibits the exercise of, or is-conditioned on the non-exercise of one or more of the rights that are-specifically granted under this License. You may not convey a covered-work if you are a party to an arrangement with a third party that is-in the business of distributing software, under which you make payment-to the third party based on the extent of your activity of conveying-the work, and under which the third party grants, to any of the-parties who would receive the covered work from you, a discriminatory-patent license (a) in connection with copies of the covered work-conveyed by you (or copies made from those copies), or (b) primarily-for and in connection with specific products or compilations that-contain the covered work, unless you entered into that arrangement,-or that patent license was granted, prior to 28 March 2007.-- Nothing in this License shall be construed as excluding or limiting-any implied license or other defenses to infringement that may-otherwise be available to you under applicable patent law.-- 12. No Surrender of Others' Freedom.-- If conditions are imposed on you (whether by court order, agreement or-otherwise) that contradict the conditions of this License, they do not-excuse you from the conditions of this License. If you cannot convey a-covered work so as to satisfy simultaneously your obligations under this-License and any other pertinent obligations, then as a consequence you may-not convey it at all. For example, if you agree to terms that obligate you-to collect a royalty for further conveying from those to whom you convey-the Program, the only way you could satisfy both those terms and this-License would be to refrain entirely from conveying the Program.-- 13. Use with the GNU Affero General Public License.-- Notwithstanding any other provision of this License, you have-permission to link or combine any covered work with a work licensed-under version 3 of the GNU Affero General Public License into a single-combined work, and to convey the resulting work. The terms of this-License will continue to apply to the part which is the covered work,-but the special requirements of the GNU Affero General Public License,-section 13, concerning interaction through a network will apply to the-combination as such.-- 14. Revised Versions of this License.-- The Free Software Foundation may publish revised and/or new versions of-the GNU General Public License from time to time. Such new versions will-be similar in spirit to the present version, but may differ in detail to-address new problems or concerns.-- Each version is given a distinguishing version number. If the-Program specifies that a certain numbered version of the GNU General-Public License "or any later version" applies to it, you have the-option of following the terms and conditions either of that numbered-version or of any later version published by the Free Software-Foundation. If the Program does not specify a version number of the-GNU General Public License, you may choose any version ever published-by the Free Software Foundation.-- If the Program specifies that a proxy can decide which future-versions of the GNU General Public License can be used, that proxy's-public statement of acceptance of a version permanently authorizes you-to choose that version for the Program.-- Later license versions may give you additional or different-permissions. However, no additional obligations are imposed on any-author or copyright holder as a result of your choosing to follow a-later version.-- 15. Disclaimer of Warranty.-- THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY-APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT-HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY-OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,-THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR-PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM-IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF-ALL NECESSARY SERVICING, REPAIR OR CORRECTION.-- 16. Limitation of Liability.-- IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING-WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS-THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY-GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE-USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF-DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD-PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),-EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF-SUCH DAMAGES.-- 17. Interpretation of Sections 15 and 16.-- If the disclaimer of warranty and limitation of liability provided-above cannot be given local legal effect according to their terms,-reviewing courts shall apply local law that most closely approximates-an absolute waiver of all civil liability in connection with the-Program, unless a warranty or assumption of liability accompanies a-copy of the Program in return for a fee.-- END OF TERMS AND CONDITIONS-- How to Apply These Terms to Your New Programs-- If you develop a new program, and you want it to be of the greatest-possible use to the public, the best way to achieve this is to make it-free software which everyone can redistribute and change under these terms.-- To do so, attach the following notices to the program. It is safest-to attach them to the start of each source file to most effectively-state the exclusion of warranty; and each file should have at least-the "copyright" line and a pointer to where the full notice is found.-- <one line to give the program's name and a brief idea of what it does.>- Copyright (C) <year> <name of author>-- This program is free software: you can redistribute it and/or modify- it under the terms of the GNU General Public License as published by- the Free Software Foundation, either version 3 of the License, or- (at your option) any later version.-- This program is distributed in the hope that it will be useful,- but WITHOUT ANY WARRANTY; without even the implied warranty of- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the- GNU General Public License for more details.-- You should have received a copy of the GNU General Public License- along with this program. If not, see <http://www.gnu.org/licenses/>.--Also add information on how to contact you by electronic and paper mail.-- If the program does terminal interaction, make it output a short-notice like this when it starts in an interactive mode:-- <program> Copyright (C) <year> <name of author>- This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.- This is free software, and you are welcome to redistribute it- under certain conditions; type `show c' for details.--The hypothetical commands `show w' and `show c' should show the appropriate-parts of the General Public License. Of course, your program's commands-might be different; for a GUI interface, you would use an "about box".-- You should also get your employer (if you work as a programmer) or school,-if any, to sign a "copyright disclaimer" for the program, if necessary.-For more information on this, and how to apply and follow the GNU GPL, see-<http://www.gnu.org/licenses/>.-- The GNU General Public License does not permit incorporating your program-into proprietary programs. If your program is a subroutine library, you-may consider it more useful to permit linking proprietary applications with-the library. If this is what you want to do, use the GNU Lesser General-Public License instead of this License. But first, please read-<http://www.gnu.org/philosophy/why-not-lgpl.html>.-+ GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. +
+ QuickCheck.hs view
@@ -0,0 +1,105 @@+{-# LANGUAGE GADTs #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE TypeSynonymInstances #-} +{-# LANGUAGE EmptyDataDecls #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE OverlappingInstances #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE StandaloneDeriving #-} + +module Main where + +import Generics.MultiRec hiding (show) +import Generics.MultiRec.TH +import Test.QuickCheck +import Test.QuickCheck.Random +import Control.Monad +import Generics.MultiRec.Transformations.Main +import Generics.MultiRec.Transformations.MemoTable +import Criterion.Main + +data Tree = Leaf Int | Branch1 Tree Tree | Branch2 Tree Tree | Test [(Tree,Int)] + deriving (Show, Ord, Eq) + +data TreeAST :: * -> * where + Tree :: TreeAST Tree + +type instance Ixs TreeAST = '[ Tree ] + +data Leaf +data Branch1 +data Branch2 +data Test + +instance Constructor Leaf where + conName _ = "Leaf" +instance Constructor Branch1 where + conName _ = "Branch1" +instance Constructor Branch2 where + conName _ = "Branch2" +instance Constructor Test where + conName _ = "Test" + +type instance PF TreeAST = (C Leaf (K Int) :+: C Branch1 (I Tree :*: I Tree) :+: C Branch2 (I Tree :*: I Tree) :+: (C Test ([] :.: (I Tree :*: K Int)))) :>: Tree + +instance El TreeAST Tree where + proof = Tree + +instance Fam TreeAST where + from Tree (Leaf f0) + = Tag (L (C (K f0))) + from Tree (Branch1 f0 f1) + = Tag (R (L (C ((:*:) ((I . I0) f0) ((I . I0) f1))))) + from Tree (Branch2 f0 f1) + = Tag (R (R (L (C ((:*:) ((I . I0) f0) ((I . I0) f1)))))) + from Tree (Test f0) + = Tag (R (R (R (C (D [(I . I0) i :*: K t | (i,t) <- f0]))))) + to Tree (Tag (L (C f0))) + = Leaf (unK f0) + to Tree (Tag (R (L (C ((:*:) f0 f1))))) + = Branch1 ((unI0 . unI) f0) ((unI0 . unI) f1) + to Tree (Tag (R (R (L (C ((:*:) f0 f1)))))) + = Branch2 ((unI0 . unI) f0) ((unI0 . unI) f1) + to Tree (Tag (R (R (R (C (D f0)))))) + = Test [((unI0 . unI) t, i) | t :*: K i <- f0] + +-- $(deriveAll ''TreeAST) + +-- Straight from the QC manual +instance Arbitrary Tree where + shrink (Leaf v) = map Leaf (shrink v) + shrink (Branch1 l r) = [l,r] + shrink (Branch2 l r) = [l,r] + shrink (Test lst) = concatMap (map fst) (shrink lst) + arbitrary = sized tree' + where tree' 0 = liftM Leaf arbitrary + tree' n | n>0 = + oneof [liftM Leaf arbitrary, + liftM2 Branch1 subtree subtree, + liftM2 Branch2 subtree subtree, + liftM Test genLst] + where subtree = tree' (n `div` 2) + genLst = do m <- choose (1,n) + replicateM m (resize (n `div` m) arbitrary) + +-- Our diff property +diffCorrect :: Tree -> Tree -> Bool +diffCorrect a b = apply Tree a (diff Tree a b) == Just b + +main :: IO () +main = do + putStrLn "Generating testcases" + cases <- replicateM 40 (liftM2 (,) (generate arbitrary) (generate arbitrary)) + putStrLn "Checking correctness" + forM_ cases $ \(a,b) -> do + when (not $ diffCorrect a b) $ putStrLn "Failed diffCorrect" + putStrLn "Benchmarking" + defaultMain [ + bench "MultiRec" $ nf (map (uncurry diffCorrect)) cases + ]
+ README view
@@ -0,0 +1,24 @@+A quick guide to the example code +--------------------------------- + +All the code compiles with GHC 7.10 RC2. The package itself compiles with 7.8, +but the pattern synonyms used in the examples require 7.10. + +QuickCheck.hs contains an artificial benchmark for the MultiRec code. + +In the examples folder there are many other examples. The best way to test these +is to load each of them in GHCi as follows: + +> ghci -iexamples examples\Expr.hs + +examples/Expr.hs + The Expr example shown in the paper + +examples/MultiRec.hs + The AST example shown in the paper + +examples/Regular.hs + Examples using the Regular library + +examples/LUA.hs + The Lua code example shown in the paper.
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple-main = defaultMain+import Distribution.Simple +main = defaultMain
examples/Datatypes.hs view
@@ -1,81 +1,81 @@--module Datatypes (- Tree (..), exTree1, exTree2, exTree3, exTree4, exTree5,- List (..), toL, fromL, exLst1, exLst2,- X (..), exX1, exX2,- Zig (..), Zag (..), zigzag, zigzag2,- Expr, prog1, prog2, prog3, prog4, prog5, prog6,- module Lang- ) where--import Lang-import Data.List ( unfoldr )------------------------------------------------------------------------------------- Example datatypes-------------------------------------------------------------------------------------Trees-data Tree = Leaf Int | Bin Tree Tree deriving (Show, Eq)--exTree1, exTree2, exTree3, exTree4, exTree5 :: Tree-exTree1 = Bin (Leaf 0) (Leaf 1)-exTree2 = Bin (Leaf 1) (Leaf 0)-exTree3 = Bin (Leaf 2) (Leaf 3)-exTree4 = Bin exTree2 exTree3-exTree5 = Bin exTree3 exTree4---- Lists-data List a = Nil | Cons a (List a) deriving (Eq, Show)--toL :: [a] -> List a-toL = foldr Cons Nil--fromL :: List a -> [a]-fromL = unfoldr f where- f Nil = Nothing- f (Cons h t) = Just (h,t)--exLst1, exLst2 :: List Int-exLst1 = Cons 1 $ Cons 2 $ Cons 3 $ Cons 4 Nil-exLst2 = Cons 4 $ Cons 2 $ Cons 3 $ Cons 1 Nil---- Something more exotic-data X = XA X | XB X | XC X X | XD Int deriving (Show, Eq)--exX1, exX2 :: X-exX1 = XA (XA (XA (XC (XD 1) (XD 2))))-exX2 = XA (XB (XA (XA (XB (XC (XD 2) (XD 1))))))---- Mutually recursive-data Zig = Zig1 Zig | Zig2 Zag | Zig3 deriving (Show, Eq)-data Zag = Zag1 Zag | Zag2 Zig | Zag3 deriving (Show, Eq)--zigzag :: Zig-zigzag = Zig1 (Zig2 (Zag2 Zig3))--zigzag2 :: Zig-zigzag2 = Zig2 (Zag1 (Zag2 Zig3))---- Example from paper (imported from Lang)-type Expr = AExpr--progFragment1, progFragment2 :: String-progFragment1 = "a := 1;"- ++ "b := a + 2;"- ++ "if b > 3"- ++ "then a := 2"- ++ "else b := 1;"-progFragment2 = "a := 1;"- ++ "b := a + 2;"- ++ "if not b > 3"- ++ "then b := 1"- ++ "else a := 2;"--prog1, prog2, prog3, prog4, prog5, prog6 :: Stmt-prog1 = parseString . init . concat . replicate 1 $ progFragment1-prog2 = parseString . init . concat . replicate 1 $ progFragment2-prog3 = parseString . init . concat . replicate 4 $ progFragment1-prog4 = parseString . init . concat . replicate 4 $ progFragment2-prog5 = parseString . init . concat . replicate 5 $ progFragment1-prog6 = parseString . init . concat . replicate 5 $ progFragment2+ +module Datatypes ( + Tree (..), exTree1, exTree2, exTree3, exTree4, exTree5, + List (..), toL, fromL, exLst1, exLst2, + X (..), exX1, exX2, + Zig (..), Zag (..), zigzag, zigzag2, + Expr, prog1, prog2, prog3, prog4, prog5, prog6, + module Lang + ) where + +import Lang +import Data.List ( unfoldr ) + +-------------------------------------------------------------------------------- +-- Example datatypes +-------------------------------------------------------------------------------- + +--Trees +data Tree = Leaf Int | Bin Tree Tree deriving (Show, Eq) + +exTree1, exTree2, exTree3, exTree4, exTree5 :: Tree +exTree1 = Bin (Leaf 0) (Leaf 1) +exTree2 = Bin (Leaf 1) (Leaf 0) +exTree3 = Bin (Leaf 2) (Leaf 3) +exTree4 = Bin exTree2 exTree3 +exTree5 = Bin exTree3 exTree4 + +-- Lists +data List a = Nil | Cons a (List a) deriving (Eq, Show) + +toL :: [a] -> List a +toL = foldr Cons Nil + +fromL :: List a -> [a] +fromL = unfoldr f where + f Nil = Nothing + f (Cons h t) = Just (h,t) + +exLst1, exLst2 :: List Int +exLst1 = Cons 1 $ Cons 2 $ Cons 3 $ Cons 4 Nil +exLst2 = Cons 4 $ Cons 2 $ Cons 3 $ Cons 1 Nil + +-- Something more exotic +data X = XA X | XB X | XC X X | XD Int deriving (Show, Eq) + +exX1, exX2 :: X +exX1 = XA (XA (XA (XC (XD 1) (XD 2)))) +exX2 = XA (XB (XA (XA (XB (XC (XD 2) (XD 1)))))) + +-- Mutually recursive +data Zig = Zig1 Zig | Zig2 Zag | Zig3 deriving (Show, Eq) +data Zag = Zag1 Zag | Zag2 Zig | Zag3 deriving (Show, Eq) + +zigzag :: Zig +zigzag = Zig1 (Zig2 (Zag2 Zig3)) + +zigzag2 :: Zig +zigzag2 = Zig2 (Zag1 (Zag2 Zig3)) + +-- Example from paper (imported from Lang) +type Expr = AExpr + +progFragment1, progFragment2 :: String +progFragment1 = "a := 1;" + ++ "b := a + 2;" + ++ "if b > 3" + ++ "then a := 2" + ++ "else b := 1;" +progFragment2 = "a := 1;" + ++ "b := a + 2;" + ++ "if not b > 3" + ++ "then b := 1" + ++ "else a := 2;" + +prog1, prog2, prog3, prog4, prog5, prog6 :: Stmt +prog1 = parseString . init . concat . replicate 1 $ progFragment1 +prog2 = parseString . init . concat . replicate 1 $ progFragment2 +prog3 = parseString . init . concat . replicate 4 $ progFragment1 +prog4 = parseString . init . concat . replicate 4 $ progFragment2 +prog5 = parseString . init . concat . replicate 5 $ progFragment1 +prog6 = parseString . init . concat . replicate 5 $ progFragment2
+ examples/Expr.hs view
@@ -0,0 +1,58 @@+{-# LANGUAGE GADTs #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE TypeSynonymInstances #-} +{-# LANGUAGE EmptyDataDecls #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE OverlappingInstances #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE PatternSynonyms #-} + +module Main where + +import Generics.MultiRec hiding (show) +import Generics.MultiRec.TH +import Test.QuickCheck +import Test.QuickCheck.Random +import Control.Monad +import Generics.MultiRec.Transformations.Main +import Generics.MultiRec.Transformations.MemoTable + +data Expr = Var String + | Const Int + | Neg Expr + | Add Expr Expr + deriving (Show, Ord, Eq) + +data ExprAST :: * -> * where + Expr :: ExprAST Expr + +type instance Ixs ExprAST = '[ Expr ] + +$(deriveAll ''ExprAST) + +instance Arbitrary Expr where + shrink (Var v) = map Var (shrink v) + shrink (Const v) = map Const (shrink v) + shrink (Neg l) = [l] + shrink (Add l r) = [l,r] + + arbitrary = sized expr' + where expr' 0 = oneof [liftM Var arbitrary, liftM Const arbitrary] + expr' n | n>0 = + oneof [ liftM Var arbitrary + , liftM Const arbitrary + , liftM Neg (expr' (pred n)) + , liftM2 Add subtree subtree ] + where subtree = expr' (n `div` 2) + +expr1, expr2, expr3 :: Expr +expr1 = Add (Const 1) (Var "a") +expr2 = Add (Const 1) (Neg (Var "a")) +expr3 = Add (Var "a") (Const 1)
+ examples/LUA.hs view
@@ -0,0 +1,715 @@+{-# LANGUAGE GADTs #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE CPP #-} + +import Control.Monad +import qualified Language.Lua as LUA -- from language-lua +import Generics.MultiRec hiding (show) +import Generics.MultiRec.Transformations.Main + +-- From https://github.com/leafo/lapis/commits/629c559094df41694bea0a33a2be75115c544dad/lapis/application.lua +files :: [FilePath] +files = ["examples/LUA_project/" ++ f + | f <- [ "application.lua." ++ show n | n <- [1..90] ] ] + +-------------------------------------------------------------------------------- +-- Main +-------------------------------------------------------------------------------- +main :: IO () +main = do + putStrLn "Parsing" + psr <- forM files $ LUA.parseFile + let ps = [ (p,f) | (Right p,f) <- zip psr files ] + putStrLn "Diffing" + forM_ (zip ps (tail ps)) $ \((p1,f1),(p2,f2)) -> do + putStrLn $ f1 ++ " --> " ++ f2 + let df = diff Block p1 p2 + print $ length df + print $ apply Block p1 df == Just p2 + +-------------------------------------------------------------------------------- +-- Multirec instance +-------------------------------------------------------------------------------- +data AST :: * -> * where + Stat :: AST LUA.Stat + Exp :: AST LUA.Exp + Var :: AST LUA.Var + Binop :: AST LUA.Binop + Unop :: AST LUA.Unop + PrefixExp :: AST LUA.PrefixExp + TableField :: AST LUA.TableField + Block :: AST LUA.Block + FunName :: AST LUA.FunName + FunBody :: AST LUA.FunBody + FunCall :: AST LUA.FunCall + FunArg :: AST LUA.FunArg + +deriving instance Ord LUA.Stat +deriving instance Ord LUA.Exp +deriving instance Ord LUA.Var +deriving instance Ord LUA.Binop +deriving instance Ord LUA.Unop +deriving instance Ord LUA.PrefixExp +deriving instance Ord LUA.TableField +deriving instance Ord LUA.Block +deriving instance Ord LUA.FunName +deriving instance Ord LUA.FunBody +deriving instance Ord LUA.FunCall +deriving instance Ord LUA.FunArg + + +#if OLD_APPROACH +instance Transform AST + +instance OrdI AST where + indexI Stat = 0 + indexI Exp = 1 + indexI Var = 2 + indexI Binop = 3 + indexI Unop = 4 + indexI PrefixExp = 5 + indexI TableField = 6 + indexI Block = 7 + indexI FunName = 8 + indexI FunBody = 9 + indexI FunCall = 10 + indexI FunArg = 11 +#else +type instance Ixs AST = '[ LUA.Stat, LUA.Exp, LUA.Var, LUA.Binop, LUA.Unop, LUA.PrefixExp, LUA.TableField, LUA.Block, LUA.FunName, LUA.FunBody, LUA.FunCall, LUA.FunArg ] +#endif + +-- Automatically generated and manually edited +data Assign +data FunCall +data Label +data Break +data Goto +data Do +data While +data Repeat +data If +data ForRange +data ForIn +data FunAssign +data LocalFunAssign +data LocalAssign +data EmptyStat +instance Constructor Assign where + conName _ = "Assign" +instance Constructor FunCall where + conName _ = "FunCall" +instance Constructor Label where + conName _ = "Label" +instance Constructor Break where + conName _ = "Break" +instance Constructor Goto where + conName _ = "Goto" +instance Constructor Do where + conName _ = "Do" +instance Constructor While where + conName _ = "While" +instance Constructor Repeat where + conName _ = "Repeat" +instance Constructor If where + conName _ = "If" +instance Constructor ForRange where + conName _ = "ForRange" +instance Constructor ForIn where + conName _ = "ForIn" +instance Constructor FunAssign where + conName _ = "FunAssign" +instance Constructor LocalFunAssign where + conName _ = "LocalFunAssign" +instance Constructor LocalAssign where + conName _ = "LocalAssign" +instance Constructor EmptyStat where + conName _ = "EmptyStat" +data Nil +data LBool +data Number +data LString +data Vararg +data EFunDef +data PrefixExp +data TableConst +data Binop +data Unop +instance Constructor Nil where + conName _ = "Nil" +instance Constructor LBool where + conName _ = "Bool" +instance Constructor Number where + conName _ = "Number" +instance Constructor LString where + conName _ = "String" +instance Constructor Vararg where + conName _ = "Vararg" +instance Constructor EFunDef where + conName _ = "EFunDef" +instance Constructor PrefixExp where + conName _ = "PrefixExp" +instance Constructor TableConst where + conName _ = "TableConst" +instance Constructor Binop where + conName _ = "Binop" +instance Constructor Unop where + conName _ = "Unop" +data VarName +data Select +data SelectName +instance Constructor VarName where + conName _ = "VarName" +instance Constructor Select where + conName _ = "Select" +instance Constructor SelectName where + conName _ = "SelectName" +data Add +data Sub +data Mul +data Div +data Exp +data Mod +data Concat +data LT +data LTE +data GT +data GTE +data EQ +data NEQ +data And +data Or +instance Constructor Add where + conName _ = "Add" +instance Constructor Sub where + conName _ = "Sub" +instance Constructor Mul where + conName _ = "Mul" +instance Constructor Div where + conName _ = "Div" +instance Constructor Exp where + conName _ = "Exp" +instance Constructor Mod where + conName _ = "Mod" +instance Constructor Concat where + conName _ = "Concat" +instance Constructor LT where + conName _ = "LT" +instance Constructor LTE where + conName _ = "LTE" +instance Constructor GT where + conName _ = "GT" +instance Constructor GTE where + conName _ = "GTE" +instance Constructor EQ where + conName _ = "EQ" +instance Constructor NEQ where + conName _ = "NEQ" +instance Constructor And where + conName _ = "And" +instance Constructor Or where + conName _ = "Or" +data Neg +data Not +data Len +instance Constructor Neg where + conName _ = "Neg" +instance Constructor Not where + conName _ = "Not" +instance Constructor Len where + conName _ = "Len" +data PEVar +data PEFunCall +data Paren +instance Constructor PEVar where + conName _ = "PEVar" +instance Constructor PEFunCall where + conName _ = "PEFunCall" +instance Constructor Paren where + conName _ = "Paren" +data ExpField +data NamedField +data Field +instance Constructor ExpField where + conName _ = "ExpField" +instance Constructor NamedField where + conName _ = "NamedField" +instance Constructor Field where + conName _ = "Field" +data Block +instance Constructor Block where + conName _ = "Block" +data FunName +instance Constructor FunName where + conName _ = "FunName" +data FunBody +instance Constructor FunBody where + conName _ = "FunBody" +data NormalFunCall +data MethodCall +instance Constructor NormalFunCall where + conName _ = "NormalFunCall" +instance Constructor MethodCall where + conName _ = "MethodCall" +data Args +data TableArg +data StringArg +instance Constructor Args where + conName _ = "Args" +instance Constructor TableArg where + conName _ = "TableArg" +instance Constructor StringArg where + conName _ = "StringArg" + +type instance PF AST = (:+:) ((:>:) + ((:+:) (C Assign ((:*:) ((:.:) [] (I LUA.Var)) ((:.:) [] (I LUA.Exp)))) + ((:+:) (C FunCall (I LUA.FunCall)) + ((:+:) (C Label (K LUA.Name)) + ((:+:) (C Break U) + ((:+:) (C Goto (K LUA.Name)) + ((:+:) (C Do (I LUA.Block)) + ((:+:) (C While ((:*:) (I LUA.Exp) (I LUA.Block))) + ((:+:) (C Repeat ((:*:) (I LUA.Block) (I LUA.Exp))) + ((:+:) (C If ((:*:) ((:.:) [] ((:*:) (I LUA.Exp) (I LUA.Block))) ((:.:) Maybe (I LUA.Block)))) -- Manually changed, is it correct? + ((:+:) (C ForRange ((:*:) (K LUA.Name) ((:*:) (I LUA.Exp) ((:*:) (I LUA.Exp) ((:*:) ((:.:) Maybe (I LUA.Exp)) (I LUA.Block)))))) + ((:+:) (C ForIn ((:*:) ((:.:) [] (K LUA.Name)) ((:*:) ((:.:) [] (I LUA.Exp)) (I LUA.Block)))) + ((:+:) (C FunAssign ((:*:) (I LUA.FunName) (I LUA.FunBody))) + ((:+:) (C LocalFunAssign ((:*:) (K LUA.Name) (I LUA.FunBody))) + ((:+:) (C LocalAssign ((:*:) ((:.:) [] (K LUA.Name)) ((:.:) Maybe ((:.:) [] (I LUA.Exp))))) + (C EmptyStat U))))))))))))))) LUA.Stat) ((:+:) ((:>:) + ((:+:) (C Nil U) + ((:+:) (C LBool (K Bool)) + ((:+:) (C Number (K String)) + ((:+:) (C LString (K String)) + ((:+:) (C Vararg U) + ((:+:) (C EFunDef (I LUA.FunBody)) + ((:+:) (C PrefixExp (I LUA.PrefixExp)) + ((:+:) (C TableConst ((:.:) [] (I LUA.TableField))) + ((:+:) (C Binop ((:*:) (I LUA.Binop) ((:*:) (I LUA.Exp) (I LUA.Exp)))) + (C Unop ((:*:) (I LUA.Unop) (I LUA.Exp)))))))))))) LUA.Exp) ((:+:) ((:>:) + ((:+:) (C VarName (K LUA.Name)) + ((:+:) (C Select ((:*:) (I LUA.PrefixExp) (I LUA.Exp))) (C SelectName ((:*:) (I LUA.PrefixExp) (K LUA.Name))))) LUA.Var) ((:+:) ((:>:) + ((:+:) (C Add U) + ((:+:) (C Sub U) + ((:+:) (C Mul U) + ((:+:) (C Div U) + ((:+:) (C Exp U) + ((:+:) (C Mod U) + ((:+:) (C Concat U) + ((:+:) (C LT U) + ((:+:) (C LTE U) + ((:+:) (C GT U) + ((:+:) (C GTE U) + ((:+:) (C EQ U) + ((:+:) (C NEQ U) + ((:+:) (C And U) (C Or U))))))))))))))) LUA.Binop) + ((:+:) ((:>:) + ((:+:) (C Neg U) + ((:+:) (C Not U) (C Len U))) LUA.Unop) + ((:+:) ((:>:) + ((:+:) (C PEVar (I LUA.Var)) + ((:+:) (C PEFunCall (I LUA.FunCall)) (C Paren (I LUA.Exp)))) LUA.PrefixExp) + ((:+:) ((:>:) + ((:+:) (C ExpField ((:*:) (I LUA.Exp) (I LUA.Exp))) + ((:+:) (C NamedField ((:*:) (K LUA.Name) (I LUA.Exp))) (C Field (I LUA.Exp)))) LUA.TableField) + ((:+:) ((:>:) (C Block ((:*:) ((:.:) [] (I LUA.Stat)) ((:.:) Maybe ((:.:) [] (I LUA.Exp))))) LUA.Block) + ((:+:) ((:>:) (C FunName ((:*:) (K LUA.Name) ((:*:) ((:.:) [] (K LUA.Name)) ((:.:) Maybe (K LUA.Name))))) LUA.FunName) + ((:+:) ((:>:) (C FunBody ((:*:) ((:.:) [] (K LUA.Name)) ((:*:) (K Bool) (I LUA.Block)))) LUA.FunBody) + ((:+:) ((:>:) + ((:+:) (C NormalFunCall ((:*:) (I LUA.PrefixExp) (I LUA.FunArg))) (C MethodCall ((:*:) (I LUA.PrefixExp) ((:*:) (K LUA.Name) (I LUA.FunArg))))) LUA.FunCall) ((:>:) + ((:+:) (C Args ((:.:) [] (I LUA.Exp))) + ((:+:) (C TableArg ((:.:) [] (I LUA.TableField))) (C StringArg (K String)))) LUA.FunArg))))))))))) + +instance El AST LUA.Stat where + proof = Stat +instance El AST LUA.Exp where + proof = Exp +instance El AST LUA.Var where + proof = Var +instance El AST LUA.Binop where + proof = Binop +instance El AST LUA.Unop where + proof = Unop +instance El AST LUA.PrefixExp where + proof = PrefixExp +instance El AST LUA.TableField where + proof = TableField +instance El AST LUA.Block where + proof = Block +instance El AST LUA.FunName where + proof = FunName +instance El AST LUA.FunBody where + proof = FunBody +instance El AST LUA.FunCall where + proof = FunCall +instance El AST LUA.FunArg where + proof = FunArg +instance Fam AST where + from Stat (LUA.Assign f0 f1) + = L (Tag + (L (C ((:*:) + ((D . (fmap (I . I0))) f0) ((D . (fmap (I . I0))) f1))))) + from Stat (LUA.FunCall f0) + = L (Tag (R (L (C ((I . I0) f0))))) + from Stat (LUA.Label f0) = L (Tag (R (R (L (C (K f0)))))) + from Stat LUA.Break = L (Tag (R (R (R (L (C U)))))) + from Stat (LUA.Goto f0) = L (Tag (R (R (R (R (L (C (K f0)))))))) + from Stat (LUA.Do f0) + = L (Tag (R (R (R (R (R (L (C ((I . I0) f0))))))))) + from Stat (LUA.While f0 f1) + = L (Tag + (R (R (R (R (R (R (L (C ((:*:) + ((I . I0) f0) ((I . I0) f1))))))))))) + from Stat (LUA.Repeat f0 f1) + = L (Tag + (R (R (R (R (R (R (R (L (C ((:*:) + ((I . I0) f0) ((I . I0) f1)))))))))))) + from Stat (LUA.If f0 f1) + = L (Tag + (R (R (R (R (R (R (R (R (L (C ((:*:) + (D [((I . I0) e :*: (I . I0) b) | (e, b) <- f0]) + ((D . (fmap (I . I0))) f1))))))))))))) + from Stat (LUA.ForRange f0 f1 f2 f3 f4) + = L (Tag + (R (R (R (R (R (R (R (R (R (L (C ((:*:) + (K f0) + ((:*:) + ((I . I0) f1) + ((:*:) + ((I . I0) f2) + ((:*:) + ((D . (fmap (I . I0))) f3) + ((I . I0) f4))))))))))))))))) + from Stat (LUA.ForIn f0 f1 f2) + = L (Tag + (R (R (R (R (R (R (R (R (R (R (L (C ((:*:) + ((D . (fmap K)) f0) + ((:*:) + ((D . (fmap (I . I0))) f1) + ((I . I0) f2)))))))))))))))) + from Stat (LUA.FunAssign f0 f1) + = L (Tag + (R (R (R (R (R (R (R (R (R (R (R (L (C ((:*:) + ((I . I0) f0) ((I . I0) f1)))))))))))))))) + from Stat (LUA.LocalFunAssign f0 f1) + = L (Tag + (R (R (R (R (R (R (R (R (R (R (R (R (L (C ((:*:) + (K f0) ((I . I0) f1))))))))))))))))) + from Stat (LUA.LocalAssign f0 f1) + = L (Tag + (R (R (R (R (R (R (R (R (R (R (R (R (R (L (C ((:*:) + ((D . (fmap K)) f0) + ((D . (fmap (D . (fmap (I . I0))))) + f1)))))))))))))))))) + from Stat LUA.EmptyStat + = L (Tag + (R (R (R (R (R (R (R (R (R (R (R (R (R (R (C U)))))))))))))))) + from Exp LUA.Nil = R (L (Tag (L (C U)))) + from Exp (LUA.Bool f0) = R (L (Tag (R (L (C (K f0)))))) + from Exp (LUA.Number f0) = R (L (Tag (R (R (L (C (K f0))))))) + from Exp (LUA.String f0) = R (L (Tag (R (R (R (L (C (K f0)))))))) + from Exp LUA.Vararg = R (L (Tag (R (R (R (R (L (C U)))))))) + from Exp (LUA.EFunDef f0) + = R (L (Tag (R (R (R (R (R (L (C ((I . I0) f0)))))))))) + from Exp (LUA.PrefixExp f0) + = R (L (Tag (R (R (R (R (R (R (L (C ((I . I0) f0))))))))))) + from Exp (LUA.TableConst f0) + = R (L (Tag + (R (R (R (R (R (R (R (L (C ((D . (fmap (I . I0))) f0)))))))))))) + from Exp (LUA.Binop f0 f1 f2) + = R (L (Tag + (R (R (R (R (R (R (R (R (L (C ((:*:) + ((I . I0) f0) + ((:*:) ((I . I0) f1) ((I . I0) f2))))))))))))))) + from Exp (LUA.Unop f0 f1) + = R (L (Tag + (R (R (R (R (R (R (R (R (R (C ((:*:) + ((I . I0) f0) ((I . I0) f1)))))))))))))) + from Var (LUA.VarName f0) = R (R (L (Tag (L (C (K f0)))))) + from Var (LUA.Select f0 f1) + = R (R (L (Tag (R (L (C ((:*:) ((I . I0) f0) ((I . I0) f1)))))))) + from Var (LUA.SelectName f0 f1) + = R (R (L (Tag (R (R (C ((:*:) ((I . I0) f0) (K f1)))))))) + from Binop LUA.Add = R (R (R (L (Tag (L (C U)))))) + from Binop LUA.Sub = R (R (R (L (Tag (R (L (C U))))))) + from Binop LUA.Mul = R (R (R (L (Tag (R (R (L (C U)))))))) + from Binop LUA.Div = R (R (R (L (Tag (R (R (R (L (C U))))))))) + from Binop LUA.Exp + = R (R (R (L (Tag (R (R (R (R (L (C U)))))))))) + from Binop LUA.Mod = R (R (R (L (Tag (R (R (R (R (R (L (C U))))))))))) + from Binop LUA.Concat + = R (R (R (L (Tag (R (R (R (R (R (R (L (C U)))))))))))) + from Binop LUA.LT + = R (R (R (L (Tag (R (R (R (R (R (R (R (L (C U))))))))))))) + from Binop LUA.LTE + = R (R (R (L (Tag (R (R (R (R (R (R (R (R (L (C U)))))))))))))) + from Binop LUA.GT + = R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (L (C U))))))))))))))) + from Binop LUA.GTE + = R (R (R (L (Tag + (R (R (R (R (R (R (R (R (R (R (L (C U)))))))))))))))) + from Binop LUA.EQ + = R (R (R (L (Tag + (R (R (R (R (R (R (R (R (R (R (R (L (C U))))))))))))))))) + from Binop LUA.NEQ + = R (R (R (L (Tag + (R (R (R (R (R (R (R (R (R (R (R (R (L (C U)))))))))))))))))) + from Binop LUA.And + = R (R (R (L (Tag + (R (R (R (R (R (R (R (R (R (R (R (R (R (L (C U))))))))))))))))))) + from Binop LUA.Or + = R (R (R (L (Tag + (R (R (R (R (R (R (R (R (R (R (R (R (R (R (C U))))))))))))))))))) + from Unop LUA.Neg = R (R (R (R (L (Tag (L (C U))))))) + from Unop LUA.Not = R (R (R (R (L (Tag (R (L (C U)))))))) + from Unop LUA.Len = R (R (R (R (L (Tag (R (R (C U)))))))) + from PrefixExp (LUA.PEVar f0) + = R (R (R (R (R (L (Tag (L (C ((I . I0) f0))))))))) + from PrefixExp (LUA.PEFunCall f0) + = R (R (R (R (R (L (Tag (R (L (C ((I . I0) f0)))))))))) + from PrefixExp (LUA.Paren f0) + = R (R (R (R (R (L (Tag (R (R (C ((I . I0) f0)))))))))) + from TableField (LUA.ExpField f0 f1) + = R (R (R (R (R (R (L (Tag + (L (C ((:*:) ((I . I0) f0) ((I . I0) f1))))))))))) + from TableField (LUA.NamedField f0 f1) + = R (R (R (R (R (R (L (Tag + (R (L (C ((:*:) (K f0) ((I . I0) f1)))))))))))) + from TableField (LUA.Field f0) + = R (R (R (R (R (R (L (Tag (R (R (C ((I . I0) f0))))))))))) + from Block (LUA.Block f0 f1) + = R (R (R (R (R (R (R (L (Tag + (C ((:*:) + ((D . (fmap (I . I0))) f0) + ((D . (fmap (D . (fmap (I . I0))))) f1))))))))))) + from FunName (LUA.FunName f0 f1 f2) + = R (R (R (R (R (R (R (R (L (Tag + (C ((:*:) + (K f0) + ((:*:) + ((D . (fmap K)) f1) ((D . (fmap K)) f2))))))))))))) + from FunBody (LUA.FunBody f0 f1 f2) + = R (R (R (R (R (R (R (R (R (L (Tag + (C ((:*:) + ((D . (fmap K)) f0) + ((:*:) (K f1) ((I . I0) f2)))))))))))))) + from FunCall (LUA.NormalFunCall f0 f1) + = R (R (R (R (R (R (R (R (R (R (L (Tag + (L (C ((:*:) ((I . I0) f0) ((I . I0) f1))))))))))))))) + from FunCall (LUA.MethodCall f0 f1 f2) + = R (R (R (R (R (R (R (R (R (R (L (Tag + (R (C ((:*:) + ((I . I0) f0) + ((:*:) (K f1) ((I . I0) f2)))))))))))))))) + from FunArg (LUA.Args f0) + = R (R (R (R (R (R (R (R (R (R (R (Tag + (L (C ((D . (fmap (I . I0))) f0)))))))))))))) + from FunArg (LUA.TableArg f0) + = R (R (R (R (R (R (R (R (R (R (R (Tag + (R (L (C ((D . (fmap (I . I0))) f0))))))))))))))) + from FunArg (LUA.StringArg f0) + = R (R (R (R (R (R (R (R (R (R (R (Tag + (R (R (C (K f0))))))))))))))) + to Stat (L (Tag (L (C ((:*:) f0 f1))))) + = LUA.Assign + (((fmap (unI0 . unI)) . unD) f0) (((fmap (unI0 . unI)) . unD) f1) + to Stat (L (Tag (R (L (C f0))))) + = LUA.FunCall ((unI0 . unI) f0) + to Stat (L (Tag (R (R (L (C f0)))))) = LUA.Label (unK f0) + to Stat (L (Tag (R (R (R (L (C U))))))) = LUA.Break + to Stat (L (Tag (R (R (R (R (L (C f0)))))))) = LUA.Goto (unK f0) + to Stat (L (Tag (R (R (R (R (R (L (C f0))))))))) + = LUA.Do ((unI0 . unI) f0) + to Stat (L (Tag (R (R (R (R (R (R (L (C ((:*:) f0 f1))))))))))) + = LUA.While ((unI0 . unI) f0) ((unI0 . unI) f1) + to Stat (L (Tag (R (R (R (R (R (R (R (L (C ((:*:) f0 f1)))))))))))) + = LUA.Repeat ((unI0 . unI) f0) ((unI0 . unI) f1) + to + Stat + (L (Tag (R (R (R (R (R (R (R (R (L (C ((:*:) f0 f1))))))))))))) + = LUA.If + [((unI0 . unI) e, (unI0 . unI) b) | (e :*: b) <- unD f0] + (((fmap (unI0 . unI)) . unD) f1) + to + Stat + (L (Tag (R (R (R (R (R (R (R (R (R (L (C ((:*:) f0 + ((:*:) f1 + ((:*:) f2 + ((:*:) f3 f4))))))))))))))))) + = LUA.ForRange + (unK f0) + ((unI0 . unI) f1) + ((unI0 . unI) f2) + (((fmap (unI0 . unI)) . unD) f3) + ((unI0 . unI) f4) + to + Stat + (L (Tag (R (R (R (R (R (R (R (R (R (R (L (C ((:*:) f0 + ((:*:) f1 f2)))))))))))))))) + = LUA.ForIn + (((fmap unK) . unD) f0) + (((fmap (unI0 . unI)) . unD) f1) + ((unI0 . unI) f2) + to + Stat + (L (Tag (R (R (R (R (R (R (R (R (R (R (R (L (C ((:*:) f0 + f1)))))))))))))))) + = LUA.FunAssign ((unI0 . unI) f0) ((unI0 . unI) f1) + to + Stat + (L (Tag (R (R (R (R (R (R (R (R (R (R (R (R (L (C ((:*:) f0 + f1))))))))))))))))) + = LUA.LocalFunAssign (unK f0) ((unI0 . unI) f1) + to + Stat + (L (Tag (R (R (R (R (R (R (R (R (R (R (R (R (R (L (C ((:*:) f0 + f1)))))))))))))))))) + = LUA.LocalAssign + (((fmap unK) . unD) f0) + (((fmap ((fmap (unI0 . unI)) . unD)) . unD) f1) + to + Stat + (L (Tag (R (R (R (R (R (R (R (R (R (R (R (R (R (R (C U))))))))))))))))) + = LUA.EmptyStat + to Exp (R (L (Tag (L (C U))))) = LUA.Nil + to Exp (R (L (Tag (R (L (C f0)))))) = LUA.Bool (unK f0) + to Exp (R (L (Tag (R (R (L (C f0))))))) = LUA.Number (unK f0) + to Exp (R (L (Tag (R (R (R (L (C f0)))))))) = LUA.String (unK f0) + to Exp (R (L (Tag (R (R (R (R (L (C U))))))))) = LUA.Vararg + to Exp (R (L (Tag (R (R (R (R (R (L (C f0)))))))))) + = LUA.EFunDef ((unI0 . unI) f0) + to Exp (R (L (Tag (R (R (R (R (R (R (L (C f0))))))))))) + = LUA.PrefixExp ((unI0 . unI) f0) + to Exp (R (L (Tag (R (R (R (R (R (R (R (L (C f0)))))))))))) + = LUA.TableConst (((fmap (unI0 . unI)) . unD) f0) + to + Exp + (R (L (Tag (R (R (R (R (R (R (R (R (L (C ((:*:) f0 + ((:*:) f1 f2))))))))))))))) + = LUA.Binop + ((unI0 . unI) f0) ((unI0 . unI) f1) ((unI0 . unI) f2) + to + Exp + (R (L (Tag (R (R (R (R (R (R (R (R (R (C ((:*:) f0 f1)))))))))))))) + = LUA.Unop ((unI0 . unI) f0) ((unI0 . unI) f1) + to Var (R (R (L (Tag (L (C f0)))))) = LUA.VarName (unK f0) + to Var (R (R (L (Tag (R (L (C ((:*:) f0 f1)))))))) + = LUA.Select ((unI0 . unI) f0) ((unI0 . unI) f1) + to Var (R (R (L (Tag (R (R (C ((:*:) f0 f1)))))))) + = LUA.SelectName ((unI0 . unI) f0) (unK f1) + to Binop (R (R (R (L (Tag (L (C U))))))) = LUA.Add + to Binop (R (R (R (L (Tag (R (L (C U)))))))) = LUA.Sub + to Binop (R (R (R (L (Tag (R (R (L (C U))))))))) = LUA.Mul + to Binop (R (R (R (L (Tag (R (R (R (L (C U)))))))))) = LUA.Div + to Binop (R (R (R (L (Tag (R (R (R (R (L (C U))))))))))) + = LUA.Exp + to Binop (R (R (R (L (Tag (R (R (R (R (R (L (C U)))))))))))) = LUA.Mod + to Binop (R (R (R (L (Tag (R (R (R (R (R (R (L (C U))))))))))))) + = LUA.Concat + to + Binop + (R (R (R (L (Tag (R (R (R (R (R (R (R (L (C U)))))))))))))) + = LUA.LT + to + Binop + (R (R (R (L (Tag (R (R (R (R (R (R (R (R (L (C U))))))))))))))) + = LUA.LTE + to + Binop + (R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (L (C U)))))))))))))))) + = LUA.GT + to + Binop + (R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (R (L (C U))))))))))))))))) + = LUA.GTE + to + Binop + (R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (R (R (L (C U)))))))))))))))))) + = LUA.EQ + to + Binop + (R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (R (R (R (L (C U))))))))))))))))))) + = LUA.NEQ + to + Binop + (R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (R (R (R (R (L (C U)))))))))))))))))))) + = LUA.And + to + Binop + (R (R (R (L (Tag (R (R (R (R (R (R (R (R (R (R (R (R (R (R (C U)))))))))))))))))))) + = LUA.Or + to Unop (R (R (R (R (L (Tag (L (C U)))))))) = LUA.Neg + to Unop (R (R (R (R (L (Tag (R (L (C U))))))))) = LUA.Not + to Unop (R (R (R (R (L (Tag (R (R (C U))))))))) = LUA.Len + to PrefixExp (R (R (R (R (R (L (Tag (L (C f0))))))))) + = LUA.PEVar ((unI0 . unI) f0) + to PrefixExp (R (R (R (R (R (L (Tag (R (L (C f0)))))))))) + = LUA.PEFunCall ((unI0 . unI) f0) + to PrefixExp (R (R (R (R (R (L (Tag (R (R (C f0)))))))))) + = LUA.Paren ((unI0 . unI) f0) + to + TableField + (R (R (R (R (R (R (L (Tag (L (C ((:*:) f0 f1))))))))))) + = LUA.ExpField ((unI0 . unI) f0) ((unI0 . unI) f1) + to + TableField + (R (R (R (R (R (R (L (Tag (R (L (C ((:*:) f0 f1)))))))))))) + = LUA.NamedField (unK f0) ((unI0 . unI) f1) + to TableField (R (R (R (R (R (R (L (Tag (R (R (C f0))))))))))) + = LUA.Field ((unI0 . unI) f0) + to Block (R (R (R (R (R (R (R (L (Tag (C ((:*:) f0 f1))))))))))) + = LUA.Block + (((fmap (unI0 . unI)) . unD) f0) + (((fmap ((fmap (unI0 . unI)) . unD)) . unD) f1) + to + FunName + (R (R (R (R (R (R (R (R (L (Tag (C ((:*:) f0 + ((:*:) f1 f2))))))))))))) + = LUA.FunName + (unK f0) (((fmap unK) . unD) f1) (((fmap unK) . unD) f2) + to + FunBody + (R (R (R (R (R (R (R (R (R (L (Tag (C ((:*:) f0 + ((:*:) f1 f2)))))))))))))) + = LUA.FunBody + (((fmap unK) . unD) f0) (unK f1) ((unI0 . unI) f2) + to + FunCall + (R (R (R (R (R (R (R (R (R (R (L (Tag (L (C ((:*:) f0 + f1))))))))))))))) + = LUA.NormalFunCall ((unI0 . unI) f0) ((unI0 . unI) f1) + to + FunCall + (R (R (R (R (R (R (R (R (R (R (L (Tag (R (C ((:*:) f0 + ((:*:) f1 f2)))))))))))))))) + = LUA.MethodCall ((unI0 . unI) f0) (unK f1) ((unI0 . unI) f2) + to + FunArg + (R (R (R (R (R (R (R (R (R (R (R (Tag (L (C f0)))))))))))))) + = LUA.Args (((fmap (unI0 . unI)) . unD) f0) + to + FunArg + (R (R (R (R (R (R (R (R (R (R (R (Tag (R (L (C f0))))))))))))))) + = LUA.TableArg (((fmap (unI0 . unI)) . unD) f0) + to + FunArg + (R (R (R (R (R (R (R (R (R (R (R (Tag (R (R (C f0))))))))))))))) + = LUA.StringArg (unK f0) + +instance EqS AST where + eqS Stat Stat = Just Refl + eqS Exp Exp = Just Refl + eqS Var Var = Just Refl + eqS Binop Binop = Just Refl + eqS Unop Unop = Just Refl + eqS PrefixExp PrefixExp = Just Refl + eqS TableField TableField = Just Refl + eqS Block Block = Just Refl + eqS FunName FunName = Just Refl + eqS FunBody FunBody = Just Refl + eqS FunCall FunCall = Just Refl + eqS FunArg FunArg = Just Refl + eqS _ _ = Nothing
+ examples/LUA_project/application.lua.1 view
@@ -0,0 +1,733 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local lapis_config = require("lapis.config") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local increment_perf +do + local _obj_0 = require("lapis.nginx.context") + increment_perf = _obj_0.increment_perf +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local insert +do + local _obj_0 = table + insert = _obj_0.insert +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-Type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-Type"] = ct + end + end + if not self.res.headers["Content-Type"] then + self.res.headers["Content-Type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + return "" + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + local config = lapis_config.get() + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local start_time + if config.measure_performance then + ngx.update_time() + start_time = ngx.now() + end + local view = widget(self.options.locals) + if self.layout_opts then + self.layout_opts.view_widget = view + end + view:include_helper(self) + self:write(view) + if start_time then + ngx.update_time() + increment_perf("view_time", ngx.now() - start_time) + end + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local start_time + if config.measure_performance then + ngx.update_time() + start_time = ngx.now() + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + if start_time then + ngx.update_time() + increment_perf("layout_time", ngx.now() - start_time) + end + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + do + local extra = self.app.cookie_attributes(self, k, v) + if extra then + cookie = cookie .. ("; " .. extra) + end + end + self.res:add_header("Set-Cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + if type(fn) == "function" then + return fn(self) + end + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.ordered_routes = self.ordered_routes or { } + local key + if route_name then + local tuple = self.ordered_routes[route_name] + do + local old_path = tuple and tuple[next(tuple)] + if old_path then + if old_path ~= path then + error("named route mismatch (" .. tostring(old_path) .. " != " .. tostring(path) .. ")") + end + end + end + if tuple then + key = tuple + else + tuple = { + [route_name] = path + } + self.ordered_routes[route_name] = tuple + key = tuple + end + else + key = path + end + if not (self[key]) then + insert(self.ordered_routes, key) + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + do + local ordered = self.ordered_routes + if ordered then + for _index_0 = 1, #ordered do + local path = ordered[_index_0] + add_route(path, self[path]) + end + else + for path, handler in pairs(self) do + add_route(path, handler) + end + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace, error_page) + if error_page == nil then + error_page = self.app.error_page + end + local r = self.app.Request(self, self.req, self.res) + local config = lapis_config.get() + if config._name == "test" then + local param_dump = logger.flatten_params(self.url_params) + r.res:add_header("X-Lapis-Error", "true") + r:write({ + status = 500, + json = { + status = "[" .. tostring(r.req.cmd_mth) .. "] " .. tostring(r.req.cmd_url) .. " " .. tostring(param_dump), + err = err, + trace = trace + } + }) + else + r:write({ + status = 500, + layout = false, + content_type = "text/html", + error_page({ + status = 500, + err = err, + trace = trace + }) + }) + end + r:render() + logger.request(r) + return r + end, + cookie_attributes = function(self, name, value) + return "Path=/; HttpOnly" + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg, ...) + if not (thing) then + yield_error(msg) + end + return thing, msg, ... +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.10 view
@@ -0,0 +1,655 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + if self.layout_opts then + self.layout_opts.view_widget = view + end + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + return fn(self) + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace, error_page) + if error_page == nil then + error_page = self.app.error_page + end + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg, ...) + if not (thing) then + yield_error(msg) + end + return thing, msg, ... +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.11 view
@@ -0,0 +1,655 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + if self.layout_opts then + self.layout_opts.view_widget = view + end + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + return fn(self) + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace, error_page) + if error_page == nil then + error_page = self.app.error_page + end + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.12 view
@@ -0,0 +1,652 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + return fn(self) + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace, error_page) + if error_page == nil then + error_page = self.app.error_page + end + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.13 view
@@ -0,0 +1,649 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + return fn(self) + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.14 view
@@ -0,0 +1,645 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.15 view
@@ -0,0 +1,659 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.16 view
@@ -0,0 +1,659 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.17 view
@@ -0,0 +1,659 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json") then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.18 view
@@ -0,0 +1,659 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if content_type:lower() == "application/json" then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.19 view
@@ -0,0 +1,655 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json_safe = require("cjson.safe") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if content_type:lower() == "application/json" then + local obj, err = json_safe.decode(ngx.req.get_body_data()) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.2 view
@@ -0,0 +1,724 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local lapis_config = require("lapis.config") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local increment_perf +do + local _obj_0 = require("lapis.nginx.context") + increment_perf = _obj_0.increment_perf +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local insert +do + local _obj_0 = table + insert = _obj_0.insert +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-Type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-Type"] = ct + end + end + if not self.res.headers["Content-Type"] then + self.res.headers["Content-Type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + return "" + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + local config = lapis_config.get() + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local start_time + if config.measure_performance then + ngx.update_time() + start_time = ngx.now() + end + local view = widget(self.options.locals) + if self.layout_opts then + self.layout_opts.view_widget = view + end + view:include_helper(self) + self:write(view) + if start_time then + ngx.update_time() + increment_perf("view_time", ngx.now() - start_time) + end + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + do + local extra = self.app.cookie_attributes(self, k, v) + if extra then + cookie = cookie .. ("; " .. extra) + end + end + self.res:add_header("Set-Cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + if type(fn) == "function" then + return fn(self) + end + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.ordered_routes = self.ordered_routes or { } + local key + if route_name then + local tuple = self.ordered_routes[route_name] + do + local old_path = tuple and tuple[next(tuple)] + if old_path then + if old_path ~= path then + error("named route mismatch (" .. tostring(old_path) .. " != " .. tostring(path) .. ")") + end + end + end + if tuple then + key = tuple + else + tuple = { + [route_name] = path + } + self.ordered_routes[route_name] = tuple + key = tuple + end + else + key = path + end + if not (self[key]) then + insert(self.ordered_routes, key) + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + do + local ordered = self.ordered_routes + if ordered then + for _index_0 = 1, #ordered do + local path = ordered[_index_0] + add_route(path, self[path]) + end + else + for path, handler in pairs(self) do + add_route(path, handler) + end + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace, error_page) + if error_page == nil then + error_page = self.app.error_page + end + local r = self.app.Request(self, self.req, self.res) + local config = lapis_config.get() + if config._name == "test" then + local param_dump = logger.flatten_params(self.url_params) + r.res:add_header("X-Lapis-Error", "true") + r:write({ + status = 500, + json = { + status = "[" .. tostring(r.req.cmd_mth) .. "] " .. tostring(r.req.cmd_url) .. " " .. tostring(param_dump), + err = err, + trace = trace + } + }) + else + r:write({ + status = 500, + layout = false, + content_type = "text/html", + error_page({ + status = 500, + err = err, + trace = trace + }) + }) + end + r:render() + logger.request(r) + return r + end, + cookie_attributes = function(self, name, value) + return "Path=/; HttpOnly" + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg, ...) + if not (thing) then + yield_error(msg) + end + return thing, msg, ... +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.20 view
@@ -0,0 +1,597 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json_safe = require("cjson.safe") +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if content_type:lower() == "application/json" then + local obj, err = json_safe.decode(ngx.req.get_body_data()) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.21 view
@@ -0,0 +1,578 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.22 view
@@ -0,0 +1,580 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = error_response or fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.23 view
@@ -0,0 +1,580 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.24 view
@@ -0,0 +1,575 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.25 view
@@ -0,0 +1,564 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.26 view
@@ -0,0 +1,561 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.27 view
@@ -0,0 +1,545 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.28 view
@@ -0,0 +1,545 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_routes + add_routes = function(cls) + do + local parent = cls.__parent + if parent then + add_routes(parent) + end + end + for path, handler in pairs(cls.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.29 view
@@ -0,0 +1,559 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts + do + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + parts = _accum_0 + end + if not (#parts > 0) then + return + end + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + for _index_0 = 1, #extra do + local p = extra[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_routes + add_routes = function(cls) + do + local parent = cls.__parent + if parent then + add_routes(parent) + end + end + for path, handler in pairs(cls.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.3 view
@@ -0,0 +1,708 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local insert +do + local _obj_0 = table + insert = _obj_0.insert +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-Type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-Type"] = ct + end + end + if not self.res.headers["Content-Type"] then + self.res.headers["Content-Type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + return "" + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + if self.layout_opts then + self.layout_opts.view_widget = view + end + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + do + local extra = self.app.cookie_attributes(self, k, v) + if extra then + cookie = cookie .. ("; " .. extra) + end + end + self.res:add_header("Set-Cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + if type(fn) == "function" then + return fn(self) + end + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.ordered_routes = self.ordered_routes or { } + local key + if route_name then + local tuple = self.ordered_routes[route_name] + do + local old_path = tuple and tuple[next(tuple)] + if old_path then + if old_path ~= path then + error("named route mismatch (" .. tostring(old_path) .. " != " .. tostring(path) .. ")") + end + end + end + if tuple then + key = tuple + else + tuple = { + [route_name] = path + } + self.ordered_routes[route_name] = tuple + key = tuple + end + else + key = path + end + if not (self[key]) then + insert(self.ordered_routes, key) + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + do + local ordered = self.ordered_routes + if ordered then + for _index_0 = 1, #ordered do + local path = ordered[_index_0] + add_route(path, self[path]) + end + else + for path, handler in pairs(self) do + add_route(path, handler) + end + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace, error_page) + if error_page == nil then + error_page = self.app.error_page + end + local r = self.app.Request(self, self.req, self.res) + local config = require("lapis.config").get() + if config._name == "test" then + local param_dump = logger.flatten_params(self.url_params) + r.res:add_header("X-Lapis-Error", "true") + r:write({ + status = 500, + json = { + status = "[" .. tostring(r.req.cmd_mth) .. "] " .. tostring(r.req.cmd_url) .. " " .. tostring(param_dump), + err = err, + trace = trace + } + }) + else + r:write({ + status = 500, + layout = false, + content_type = "text/html", + error_page({ + status = 500, + err = err, + trace = trace + }) + }) + end + r:render() + logger.request(r) + return r + end, + cookie_attributes = function(self, name, value) + return "Path=/; HttpOnly" + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg, ...) + if not (thing) then + yield_error(msg) + end + return thing, msg, ... +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.30 view
@@ -0,0 +1,546 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts + do + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + parts = _accum_0 + end + if not (#parts > 0) then + return + end + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + for _index_0 = 1, #extra do + local p = extra[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.31 view
@@ -0,0 +1,546 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts + do + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + parts = _accum_0 + end + if not (#parts > 0) then + return + end + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + for _index_0 = 1, #extra do + local p = extra[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.32 view
@@ -0,0 +1,556 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts + do + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + parts = _accum_0 + end + if not (#parts > 0) then + return + end + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + for _index_0 = 1, #extra do + local p = extra[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.33 view
@@ -0,0 +1,558 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts + do + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + parts = _accum_0 + end + if not (#parts > 0) then + return + end + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + for _index_0 = 1, #extra do + local p = extra[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.34 view
@@ -0,0 +1,570 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts + do + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + parts = _accum_0 + end + if not (#parts > 0) then + return + end + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + for _index_0 = 1, #extra do + local p = extra[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.35 view
@@ -0,0 +1,600 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + if not (#parts > 0) then + return + end + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + local _list_0 = before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.36 view
@@ -0,0 +1,600 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + if not (#parts > 0) then + return + end + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + local _list_0 = before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.37 view
@@ -0,0 +1,600 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local capture_errors, capture_errors_json +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + if not (#parts > 0) then + return + end + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + local _list_0 = before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.38 view
@@ -0,0 +1,589 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + if not (#parts > 0) then + return + end + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + local _list_0 = before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.39 view
@@ -0,0 +1,575 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + if not (#parts > 0) then + return + end + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + local _list_0 = before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.4 view
@@ -0,0 +1,706 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local insert +do + local _obj_0 = table + insert = _obj_0.insert +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-Type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-Type"] = ct + end + end + if not self.res.headers["Content-Type"] then + self.res.headers["Content-Type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + return "" + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + if self.layout_opts then + self.layout_opts.view_widget = view + end + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + do + local extra = self.app.cookie_attributes(self, k, v) + if extra then + cookie = cookie .. ("; " .. extra) + end + end + self.res:add_header("Set-Cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + if type(fn) == "function" then + return fn(self) + end + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.ordered_routes = self.ordered_routes or { } + local key + if route_name then + local tuple = self.ordered_routes[route_name] + do + local old_path = tuple and tuple[next(tuple)] + if old_path then + if old_path ~= path then + error("named route mismatch (" .. tostring(old_path) .. " != " .. tostring(path) .. ")") + end + end + end + if tuple then + key = tuple + else + tuple = { + [route_name] = path + } + self.ordered_routes[route_name] = tuple + key = tuple + end + else + key = path + end + if not (self[key]) then + insert(self.ordered_routes, key) + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + do + local ordered = self.ordered_routes + if ordered then + for _index_0 = 1, #ordered do + local path = ordered[_index_0] + add_route(path, self[path]) + end + else + for path, handler in pairs(self) do + add_route(path, handler) + end + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace, error_page) + if error_page == nil then + error_page = self.app.error_page + end + local r = self.app.Request(self, self.req, self.res) + local config = require("lapis.config").get() + if config._name == "test" then + r.res:add_header("X-Lapis-Error", "true") + r:write({ + status = 500, + json = { + err = err, + trace = trace + } + }) + else + r:write({ + status = 500, + layout = false, + content_type = "text/html", + error_page({ + status = 500, + err = err, + trace = trace + }) + }) + end + r:render() + logger.request(r) + return r + end, + cookie_attributes = function(self, name, value) + return "Path=/; HttpOnly" + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg, ...) + if not (thing) then + yield_error(msg) + end + return thing, msg, ... +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.40 view
@@ -0,0 +1,575 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + if not (#parts > 0) then + return + end + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + local _list_0 = before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.41 view
@@ -0,0 +1,572 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + local _list_0 = before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.42 view
@@ -0,0 +1,577 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + local _list_0 = before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.43 view
@@ -0,0 +1,554 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + into[path] = action + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + into[path] = action + end + end + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.44 view
@@ -0,0 +1,527 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.45 view
@@ -0,0 +1,527 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local widget = self.options.render + if widget then + if widget == true then + widget = self.route_name + end + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + end + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.46 view
@@ -0,0 +1,525 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.47 view
@@ -0,0 +1,525 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path:match("^%a+:") then + return path + end + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.48 view
@@ -0,0 +1,522 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.49 view
@@ -0,0 +1,520 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json, build_url +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json, build_url = _table_0.parse_cookie_string, _table_0.to_json, _table_0.build_url +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + do + local old_query = parsed.query + if old_query then + parsed.query = old_query .. "&" .. query + else + parsed.query = query + end + end + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.5 view
@@ -0,0 +1,694 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local insert +do + local _obj_0 = table + insert = _obj_0.insert +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-Type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-Type"] = ct + end + end + if not self.res.headers["Content-Type"] then + self.res.headers["Content-Type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + return "" + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + if self.layout_opts then + self.layout_opts.view_widget = view + end + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + do + local extra = self.app.cookie_attributes(self, k, v) + if extra then + cookie = cookie .. ("; " .. extra) + end + end + self.res:add_header("Set-Cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + if type(fn) == "function" then + return fn(self) + end + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.ordered_routes = self.ordered_routes or { } + local key + if route_name then + local tuple = self.ordered_routes[route_name] + do + local old_path = tuple and tuple[next(tuple)] + if old_path then + if old_path ~= path then + error("named route mismatch (" .. tostring(old_path) .. " != " .. tostring(path) .. ")") + end + end + end + if tuple then + key = tuple + else + tuple = { + [route_name] = path + } + self.ordered_routes[route_name] = tuple + key = tuple + end + else + key = path + end + if not (self[key]) then + insert(self.ordered_routes, key) + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + do + local ordered = self.ordered_routes + if ordered then + for _index_0 = 1, #ordered do + local path = ordered[_index_0] + add_route(path, self[path]) + end + else + for path, handler in pairs(self) do + add_route(path, handler) + end + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace, error_page) + if error_page == nil then + error_page = self.app.error_page + end + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end, + cookie_attributes = function(self, name, value) + return "Path=/; HttpOnly" + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg, ...) + if not (thing) then + yield_error(msg) + end + return thing, msg, ... +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.50 view
@@ -0,0 +1,516 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.51 view
@@ -0,0 +1,516 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params()) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.52 view
@@ -0,0 +1,514 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params()) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + do + local extra = self.app.cookie_attributes + if extra then + i = i + 3 + local _list_0 = extra + for _index_0 = 1, #_list_0 do + local p = _list_0[_index_0] + parts[i] = p + i = i + 1 + end + end + end + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.53 view
@@ -0,0 +1,502 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params()) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.54 view
@@ -0,0 +1,502 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params()) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace) + local r = Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.app.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.55 view
@@ -0,0 +1,498 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params()) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return self.app:handle_404() + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.56 view
@@ -0,0 +1,495 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string, to_json +do + local _table_0 = require("lapis.util") + parse_cookie_string, to_json = _table_0.parse_cookie_string, _table_0.to_json +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params()) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.57 view
@@ -0,0 +1,496 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params()) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.58 view
@@ -0,0 +1,495 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params()) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.59 view
@@ -0,0 +1,495 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + url = self.options.redirect_to + if url then + if url:match("^/") then + url = self:build_url(url) + end + self.res:add_header("Location", url) + self.res.status = 302 + end + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params()) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.6 view
@@ -0,0 +1,692 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local insert +do + local _obj_0 = table + insert = _obj_0.insert +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-Type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-Type"] = ct + end + end + if not self.res.headers["Content-Type"] then + self.res.headers["Content-Type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + return "" + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + if self.layout_opts then + self.layout_opts.view_widget = view + end + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-Cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + if type(fn) == "function" then + return fn(self) + end + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.ordered_routes = self.ordered_routes or { } + local key + if route_name then + local tuple = self.ordered_routes[route_name] + do + local old_path = tuple and tuple[next(tuple)] + if old_path then + if old_path ~= path then + error("named route mismatch (" .. tostring(old_path) .. " != " .. tostring(path) .. ")") + end + end + end + if tuple then + key = tuple + else + tuple = { + [route_name] = path + } + self.ordered_routes[route_name] = tuple + key = tuple + end + else + key = path + end + if not (self[key]) then + insert(self.ordered_routes, key) + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + do + local ordered = self.ordered_routes + if ordered then + for _index_0 = 1, #ordered do + local path = ordered[_index_0] + add_route(path, self[path]) + end + else + for path, handler in pairs(self) do + add_route(path, handler) + end + end + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace, error_page) + if error_page == nil then + error_page = self.app.error_page + end + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg, ...) + if not (thing) then + yield_error(msg) + end + return thing, msg, ... +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.60 view
@@ -0,0 +1,486 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params()) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.61 view
@@ -0,0 +1,482 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.62 view
@@ -0,0 +1,481 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + if query then + path = _path + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.63 view
@@ -0,0 +1,480 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path then + local query + path, query = path:match("(.-)%?(.*)") + if query then + parsed.query = query + end + if not path:match("^/") then + path = "/" .. tostring(path) + end + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.64 view
@@ -0,0 +1,473 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + local i = #parts + parts[i + 1] = "Path=/" + parts[i + 2] = "HttpOnly" + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.65 view
@@ -0,0 +1,470 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + local layout = layout_cls({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.66 view
@@ -0,0 +1,463 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.67 view
@@ -0,0 +1,457 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.68 view
@@ -0,0 +1,453 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.69 view
@@ -0,0 +1,436 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.7 view
@@ -0,0 +1,658 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-Type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-Type"] = ct + end + end + if not self.res.headers["Content-Type"] then + self.res.headers["Content-Type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + return "" + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + if self.layout_opts then + self.layout_opts.view_widget = view + end + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-Cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + if type(fn) == "function" then + return fn(self) + end + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace, error_page) + if error_page == nil then + error_page = self.app.error_page + end + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg, ...) + if not (thing) then + yield_error(msg) + end + return thing, msg, ... +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.70 view
@@ -0,0 +1,436 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 1 + for k, v in pairs(self.cookies) do + _accum_0[_len_0] = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + _len_0 = _len_0 + 1 + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.71 view
@@ -0,0 +1,439 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +local capture_errors +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local capture_errors_json +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.72 view
@@ -0,0 +1,421 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local capture_errors +capture_errors = function(fn) + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return { + render = true + } + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + yield_error(msg) + end + return thing +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.73 view
@@ -0,0 +1,417 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + before(self) + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local capture_errors +capture_errors = function(fn) + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + self.errors = { + unpack(out, 2) + } + return { + render = true + } + else + return unpack(out, 2) + end + end +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + coroutine.yield(msg) + end + return thing +end +local yield_error +yield_error = function(msg) + return coroutine.yield(msg) +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.74 view
@@ -0,0 +1,411 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +local capture_errors +capture_errors = function(fn) + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + self.errors = { + unpack(out, 2) + } + return { + render = true + } + else + return unpack(out, 2) + end + end +end +local assert_error +assert_error = function(thing, msg) + if not (thing) then + coroutine.yield(msg) + end + return thing +end +local yield_error +yield_error = function(msg) + return coroutine.yield(msg) +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.75 view
@@ -0,0 +1,375 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + r:write(handler({ }, nil, "default_route", r)) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.cmd_url:match("./$") then + local stripped = self.req.cmd_url:match("^(.+)/+$") + return { + redirect_to = stripped, + status = 301 + } + else + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to +}
+ examples/LUA_project/application.lua.76 view
@@ -0,0 +1,358 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + end + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to +}
+ examples/LUA_project/application.lua.77 view
@@ -0,0 +1,357 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace + local success = xpcall((function() + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + local r = Request(self, req, res) + r:write({ + status = 500, + layout = false, + self.error_page({ + staus = 500, + err = err, + trace = trace + }) + }) + r:render() + end + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to +}
+ examples/LUA_project/application.lua.78 view
@@ -0,0 +1,331 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.views.layout"), + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to +}
+ examples/LUA_project/application.lua.79 view
@@ -0,0 +1,331 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.layout").Default, + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to +}
+ examples/LUA_project/application.lua.8 view
@@ -0,0 +1,658 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + return "" + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + if self.layout_opts then + self.layout_opts.view_widget = view + end + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + if type(fn) == "function" then + return fn(self) + end + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace, error_page) + if error_page == nil then + error_page = self.app.error_page + end + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg, ...) + if not (thing) then + yield_error(msg) + end + return thing, msg, ... +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.80 view
@@ -0,0 +1,330 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + view:include_helper(self) + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.layout").Default, + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to +}
+ examples/LUA_project/application.lua.81 view
@@ -0,0 +1,345 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local widget = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + local view = widget(self.options.locals) + if not (self.options.locals) then + for k, v in pairs(self) do + local _continue_0 = false + repeat + if k == "buffer" or k == "options" then + _continue_0 = true + break + end + view[k] = v + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + self:write(view) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.layout").Default, + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to +}
+ examples/LUA_project/application.lua.82 view
@@ -0,0 +1,328 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + do + local rpath = self.options.render + if rpath then + if rpath == true then + rpath = self.route_name + end + local view = require(tostring(self.app.views_prefix) .. "." .. tostring(rpath)) + self:write(view(self.options.locals or self)) + end + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.layout").Default, + views_prefix = "views", + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to +}
+ examples/LUA_project/application.lua.83 view
@@ -0,0 +1,317 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local session = require("lapis.session") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local auto_table +auto_table = function(fn) + return setmetatable({ }, { + __index = function(self, name) + local result = fn() + setmetatable(self, { + __index = result + }) + return result[name] + end + }) +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + session.write_session(self) + self:write_cookies() + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = auto_table(function() + return session.get_session(self) + end) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.layout").Default, + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to +}
+ examples/LUA_project/application.lua.84 view
@@ -0,0 +1,306 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local parse_cookie_string +do + local _table_0 = require("lapis.util") + parse_cookie_string = _table_0.parse_cookie_string +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + self:write_cookies() + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + write_cookies = function(self) + local parts = (function() + local _accum_0 = { } + local _len_0 = 0 + for k, v in pairs(self.cookies) do + local _value_0 = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) + if _value_0 ~= nil then + _len_0 = _len_0 + 1 + _accum_0[_len_0] = _value_0 + end + end + return _accum_0 + end)() + return self.res:add_header("Set-cookie", table.concat(parts, "; ")) + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = setmetatable({ }, { + __index = function(tbl, name) + local parsed = parse_cookie_string(self.req.headers.cookie) + setmetatable(self.cookies, { + __index = parsed + }) + return parsed[name] + end + }) + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.layout").Default, + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to +}
+ examples/LUA_project/application.lua.85 view
@@ -0,0 +1,276 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.layout").Default, + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +local respond_to +respond_to = function(tbl) + return function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to +}
+ examples/LUA_project/application.lua.86 view
@@ -0,0 +1,264 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.layout").Default, + before_filters = { }, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + filter(r) + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.before_filter = function(self, fn) + return table.insert(self.before_filters, fn) + end + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +return { + Request = Request, + Application = Application +}
+ examples/LUA_project/application.lua.87 view
@@ -0,0 +1,254 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local json = require("cjson") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if self.options.json then + self.res.headers["Content-type"] = "application/json" + self.res.content = json.encode(self.options.json) + return + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.layout").Default, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +return { + Request = Request, + Application = Application +}
+ examples/LUA_project/application.lua.88 view
@@ -0,0 +1,248 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.options.redirect_to then + self.res:add_header("Location", self:build_url(self.options.redirect_to)) + self.res.status = 302 + end + if self.options.status then + self.res.status = self.options.status + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + build_url = function(self, path, options) + local parsed = (function() + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + return _tbl_0 + end)() + parsed.authority = nil + if path and not path:match("^/") then + path = "/" .. tostring(path) + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return url.build(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write:", tostring(thing)) + end + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.layout").Default, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +return { + Request = Request, + Application = Application +}
+ examples/LUA_project/application.lua.89 view
@@ -0,0 +1,211 @@+local logger = require("lapis.logging") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + write = function(self, thing) + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + return table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + return self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + return nil + else + return error("Don't know how to write:", tostring(thing)) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.layout").Default, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +return { + Request = Request, + Application = Application +}
+ examples/LUA_project/application.lua.9 view
@@ -0,0 +1,656 @@+local logger = require("lapis.logging") +local url = require("socket.url") +local session = require("lapis.session") +local Router +do + local _obj_0 = require("lapis.router") + Router = _obj_0.Router +end +local html_writer +do + local _obj_0 = require("lapis.html") + html_writer = _obj_0.html_writer +end +local parse_cookie_string, to_json, build_url, auto_table +do + local _obj_0 = require("lapis.util") + parse_cookie_string, to_json, build_url, auto_table = _obj_0.parse_cookie_string, _obj_0.to_json, _obj_0.build_url, _obj_0.auto_table +end +local json = require("cjson") +local capture_errors, capture_errors_json, respond_to +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local run_before_filter +run_before_filter = function(filter, r) + local _write = r.write + local written = false + r.write = function(...) + written = true + return _write(...) + end + filter(r) + r.write = nil + return written +end +local Request +do + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + do + local front = k:match("^([^%[]+)%[") + if front then + local curr = self.params + for match in k:gmatch("%[(.-)%]") do + local new = curr[front] + if new == nil then + new = { } + curr[front] = new + end + curr = new + front = match + end + curr[front] = v + else + self.params[k] = v + end + end + end + end, + render = function(self, opts) + if opts == nil then + opts = false + end + if opts then + self.options = opts + end + session.write_session(self) + self:write_cookies() + if self.options.status then + self.res.status = self.options.status + end + do + local obj = self.options.json + if obj then + self.res.headers["Content-type"] = "application/json" + self.res.content = to_json(obj) + return + end + end + do + local ct = self.options.content_type + if ct then + self.res.headers["Content-type"] = ct + end + end + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + do + local redirect_url = self.options.redirect_to + if redirect_url then + if redirect_url:match("^/") then + redirect_url = self:build_url(redirect_url) + end + self.res:add_header("Location", redirect_url) + self.res.status = self.res.status or 302 + return "" + end + end + local has_layout = self.app.layout and set_and_truthy(self.options.layout, true) + if has_layout then + self.layout_opts = { + inner = nil + } + end + local widget = self.options.render + if widget == true then + widget = self.route_name + end + if widget then + if type(widget) == "string" then + widget = require(tostring(self.app.views_prefix) .. "." .. tostring(widget)) + end + local view = widget(self.options.locals) + if self.layout_opts then + self.layout_opts.view_widget = view + end + view:include_helper(self) + self:write(view) + end + if has_layout then + local inner = self.buffer + self.buffer = { } + local layout_path = self.options.layout + local layout_cls + if type(layout_path) == "string" then + layout_cls = require(tostring(self.app.views_prefix) .. "." .. tostring(layout_path)) + else + layout_cls = self.app.layout + end + self.layout_opts.inner = self.layout_opts.inner or function() + return raw(inner) + end + local layout = layout_cls(self.layout_opts) + layout:include_helper(self) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, first, ...) + if type(first) == "table" then + return self.app.router:url_for(first:url_params(self, ...)) + else + return self.app.router:url_for(first, ...) + end + end, + build_url = function(self, path, options) + if path and path:match("^%a+:") then + return path + end + local parsed + do + local _tbl_0 = { } + for k, v in pairs(self.req.parsed_url) do + _tbl_0[k] = v + end + parsed = _tbl_0 + end + parsed.query = nil + if path then + local _path, query = path:match("^(.-)%?(.*)$") + path = _path or path + parsed.query = query + end + parsed.path = path + if parsed.port == "80" then + parsed.port = nil + end + if options then + for k, v in pairs(options) do + parsed[k] = v + end + end + return build_url(parsed) + end, + write = function(self, ...) + local _list_0 = { + ... + } + for _index_0 = 1, #_list_0 do + local thing = _list_0[_index_0] + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + local _ = nil + else + error("Don't know how to write: (" .. tostring(t) .. ") " .. tostring(thing)) + end + end + end, + write_cookies = function(self) + if not (next(self.cookies)) then + return + end + local extra = self.app.cookie_attributes + if extra then + extra = "; " .. table.concat(self.app.cookie_attributes, "; ") + end + for k, v in pairs(self.cookies) do + local cookie = tostring(url.escape(k)) .. "=" .. tostring(url.escape(v)) .. "; Path=/; HttpOnly" + if extra then + cookie = cookie .. extra + end + self.res:add_header("Set-cookie", cookie) + end + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + self.cookies = auto_table(function() + return parse_cookie_string(self.req.headers.cookie) + end) + self.session = session.lazy_session(self) + end, + __base = _base_0, + __name = "Request" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + Request = _class_0 +end +local Application +do + local _base_0 = { + Request = Request, + layout = require("lapis.views.layout"), + error_page = require("lapis.views.error"), + views_prefix = "views", + enable = function(self, feature) + local fn = require("lapis.features." .. tostring(feature)) + return fn(self) + end, + match = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + local key + if route_name then + key = { + [route_name] = path + } + else + key = path + end + self[key] = handler + self.router = nil + return handler + end, + build_router = function(self) + self.router = Router() + self.router.default_route = function(self) + return false + end + local add_route + add_route = function(path, handler) + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + return self.router:add_route(path, self:wrap_handler(handler)) + end + end + local add_routes + add_routes = function(cls) + for path, handler in pairs(cls.__base) do + add_route(path, handler) + end + for path, handler in pairs(self) do + add_route(path, handler) + end + do + local parent = cls.__parent + if parent then + return add_routes(parent) + end + end + end + return add_routes(self.__class) + end, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(r.req.params_get, "GET") + _with_0:add_params(r.req.params_post, "POST") + _with_0:add_params(params, "url_params") + if self.before_filters then + local _list_0 = self.before_filters + for _index_0 = 1, #_list_0 do + local filter = _list_0[_index_0] + if run_before_filter(filter, r) then + return r + end + end + end + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local err, trace, r + local success = xpcall((function() + r = self.Request(self, req, res) + if not (self.router:resolve(req.parsed_url.path, r)) then + local handler = self:wrap_handler(self.default_route) + handler({ }, nil, "default_route", r) + end + r:render() + return logger.request(r) + end), function(_err) + err = _err + trace = debug.traceback("", 2) + end) + if not (success) then + self.handle_error(r, err, trace) + end + return res + end, + serve = function(self) end, + default_route = function(self) + if self.req.parsed_url.path:match("./$") then + local stripped = self.req.parsed_url.path:match("^(.+)/+$") + return { + redirect_to = self:build_url(stripped, { + query = self.req.parsed_url.query + }), + status = 301 + } + else + return self.app.handle_404(self) + end + end, + handle_404 = function(self) + return error("Failed to find route: " .. tostring(self.req.cmd_url)) + end, + handle_error = function(self, err, trace, error_page) + if error_page == nil then + error_page = self.app.error_page + end + local r = self.app.Request(self, self.req, self.res) + r:write({ + status = 500, + layout = false, + content_type = "text/html", + error_page({ + status = 500, + err = err, + trace = trace + }) + }) + r:render() + logger.request(r) + return r + end + } + _base_0.__index = _base_0 + local _class_0 = setmetatable({ + __init = function(self) + return self:build_router() + end, + __base = _base_0, + __name = "Application" + }, { + __index = _base_0, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + local self = _class_0 + self.find_action = function(self, name) + self._named_route_cache = self._named_route_cache or { } + local route = self._named_route_cache[name] + if not (route) then + for app_route in pairs(self.__base) do + if type(app_route) == "table" then + local app_route_name = next(app_route) + self._named_route_cache[app_route_name] = app_route + if app_route_name == name then + route = app_route + end + end + end + end + return route and self[route], route + end + local _list_0 = { + "get", + "post", + "delete", + "put" + } + for _index_0 = 1, #_list_0 do + local meth = _list_0[_index_0] + local upper_meth = meth:upper() + self.__base[meth] = function(self, route_name, path, handler) + if handler == nil then + handler = path + path = route_name + route_name = nil + end + self.responders = self.responders or { } + local existing = self.responders[route_name or path] + local tbl = { + [upper_meth] = handler + } + if existing then + setmetatable(tbl, { + __index = function(self, key) + if key:match("%u") then + return existing + end + end + }) + end + local responder = respond_to(tbl) + self.responders[route_name or path] = responder + return self:match(route_name, path, responder) + end + end + self.before_filter = function(self, fn) + self.__base.before_filters = self.__base.before_filters or { } + return table.insert(self.before_filters, fn) + end + self.include = function(self, other_app, opts, into) + if into == nil then + into = self.__base + end + if type(other_app) == "string" then + other_app = require(other_app) + end + local path_prefix = opts and opts.path or other_app.path + local name_prefix = opts and opts.name or other_app.name + for path, action in pairs(other_app.__base) do + local _continue_0 = false + repeat + local t = type(path) + if t == "table" then + if path_prefix then + local name = next(path) + path[name] = path_prefix .. path[name] + end + if name_prefix then + local name = next(path) + path[name_prefix .. name] = path[name] + path[name] = nil + end + elseif t == "string" and path:match("^/") then + if path_prefix then + path = path_prefix .. path + end + else + _continue_0 = true + break + end + do + local before_filters = other_app.before_filters + if before_filters then + local fn = action + action = function(r) + for _index_0 = 1, #before_filters do + local filter = before_filters[_index_0] + if run_before_filter(filter, r) then + return + end + end + return fn(r) + end + end + end + into[path] = action + _continue_0 = true + until true + if not _continue_0 then + break + end + end + end + Application = _class_0 +end +do + local default_head + default_head = function() + return { + layout = false + } + end + respond_to = function(tbl) + if not (tbl.HEAD) then + tbl.HEAD = default_head + end + local out + out = function(self) + local fn = tbl[self.req.cmd_mth] + if fn then + do + local before = tbl.before + if before then + if run_before_filter(before, self) then + return + end + end + end + return fn(self) + else + return error("don't know how to respond to " .. tostring(self.req.cmd_mth)) + end + end + do + local error_response = tbl.on_error + if error_response then + out = capture_errors(out, error_response) + end + end + return out, tbl + end +end +local default_error_response +default_error_response = function() + return { + render = true + } +end +capture_errors = function(fn, error_response) + if error_response == nil then + error_response = default_error_response + end + if type(fn) == "table" then + error_response = fn.on_error or error_response + fn = fn[1] + end + return function(self, ...) + local co = coroutine.create(fn) + local out = { + coroutine.resume(co, self) + } + if not (out[1]) then + error(debug.traceback(co, out[2])) + end + if coroutine.status(co) == "suspended" then + if out[2] == "error" then + self.errors = out[3] + return error_response(self) + else + return error("Unknown yield") + end + else + return unpack(out, 2) + end + end +end +capture_errors_json = function(fn) + return capture_errors(fn, function(self) + return { + json = { + errors = self.errors + } + } + end) +end +local yield_error +yield_error = function(msg) + return coroutine.yield("error", { + msg + }) +end +local assert_error +assert_error = function(thing, msg, ...) + if not (thing) then + yield_error(msg) + end + return thing, msg, ... +end +local json_params +json_params = function(fn) + return function(self, ...) + do + local content_type = self.req.headers["content-type"] + if content_type then + if string.find(content_type:lower(), "application/json", nil, true) then + local obj + pcall(function() + local err + obj, err = json.decode(ngx.req.get_body_data()) + end) + if obj then + self:add_params(obj, "json") + end + end + end + end + return fn(self, ...) + end +end +return { + Request = Request, + Application = Application, + respond_to = respond_to, + capture_errors = capture_errors, + capture_errors_json = capture_errors_json, + json_params = json_params, + assert_error = assert_error, + yield_error = yield_error +}
+ examples/LUA_project/application.lua.90 view
@@ -0,0 +1,209 @@+local logger = require("lapis.logging") +local Router +do + local _table_0 = require("lapis.router") + Router = _table_0.Router +end +local html_writer +do + local _table_0 = require("lapis.html") + html_writer = _table_0.html_writer +end +local set_and_truthy +set_and_truthy = function(val, default) + if default == nil then + default = true + end + if val == nil then + return default + end + return val +end +local Request +do + local _parent_0 = nil + local _base_0 = { + add_params = function(self, params, name) + self[name] = params + for k, v in pairs(params) do + self.params[k] = v + end + end, + render = function(self) + if not self.res.headers["Content-type"] then + self.res.headers["Content-type"] = "text/html" + end + if self.app.layout and set_and_truthy(self.options.layout, true) then + local inner = self.buffer + self.buffer = { } + local layout = self.app.layout({ + inner = function() + return raw(inner) + end + }) + layout:render(self.buffer) + end + if next(self.buffer) then + local content = table.concat(self.buffer) + if self.res.content then + self.res.content = self.res.content .. content + else + self.res.content = content + end + end + end, + html = function(self, fn) + return html_writer(fn) + end, + url_for = function(self, ...) + return self.app.router:url_for(...) + end, + write = function(self, thing) + local t = type(thing) + if t == "table" then + local mt = getmetatable(thing) + if mt and mt.__call then + t = "function" + end + end + local _exp_0 = t + if "string" == _exp_0 then + return table.insert(self.buffer, thing) + elseif "table" == _exp_0 then + for k, v in pairs(thing) do + if type(k) == "string" then + self.options[k] = v + else + self:write(v) + end + end + elseif "function" == _exp_0 then + return self:write(thing(self.buffer)) + elseif "nil" == _exp_0 then + return nil + else + return error("Don't know how to write:", tostring(thing)) + end + end, + _debug = function(self) + self.buffer = { + "<html>", + "req:", + "<pre>", + moon.dump(self.req), + "</pre>", + "res:", + "<pre>", + moon.dump(self.res), + "</pre>", + "</html>" + } + end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self, app, req, res) + self.app, self.req, self.res = app, req, res + self.buffer = { } + self.params = { } + self.options = { } + end, + __base = _base_0, + __name = "Request", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Request = _class_0 +end +local Application +do + local _parent_0 = nil + local _base_0 = { + layout = require("lapis.layout").Default, + wrap_handler = function(self, handler) + return function(params, path, name, r) + do + local _with_0 = r + _with_0.route_name = name + _with_0:add_params(params, "url_params") + _with_0:write(handler(r)) + return _with_0 + end + end + end, + dispatch = function(self, req, res) + local r = Request(self, req, res) + self.router:resolve(req.parsed_url.path, r) + r:render() + logger.request(r) + return res + end, + serve = function(self) end + } + _base_0.__index = _base_0 + if _parent_0 then + setmetatable(_base_0, _parent_0.__base) + end + local _class_0 = setmetatable({ + __init = function(self) + self.router = Router() + do + local _with_0 = require("lapis.server") + self.__class.__base["/static/*"] = _with_0.make_static_handler("static") + self.__class.__base["/favicon.ico"] = _with_0.serve_from_static() + end + for path, handler in pairs(self.__class.__base) do + local t = type(path) + if t == "table" or t == "string" and path:match("^/") then + self.router:add_route(path, self:wrap_handler(handler)) + end + end + end, + __base = _base_0, + __name = "Application", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil and _parent_0 then + return _parent_0[name] + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({}, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0 and _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + Application = _class_0 +end +return { + Request = Request, + Application = Application +}
examples/Lang.lhs view
@@ -1,368 +1,368 @@-Source: http://www.haskell.org/haskellwiki/Parsing_a_simple_imperative_language--This tutorial will present how to parse a subset of a simple imperative-programming language called W<small>HILE</small> (introduced in a book-"Principles of Program Analysis" by Nielson, Nielson and Hankin). It includes-only a few statements and basic boolean/arithmetic expressions, which makes it-a nice material for a tutorial.--== Imports ==--First let's specify the name of the module:--<haskell>--> module Lang where--</haskell>--And then import the necessary libraries:--<haskell>--> import System.IO-> import Control.Monad-> import Text.ParserCombinators.Parsec-> import Text.ParserCombinators.Parsec.Expr-> import Text.ParserCombinators.Parsec.Language-> import qualified Text.ParserCombinators.Parsec.Token as Token--</haskell>--== The language ==--The grammar for expressions is defined as follows:--<tt>--''a'' ::= ''x'' | ''n'' | - ''a'' | ''a'' ''opa'' ''a''--''b'' ::= true | false | not ''b'' | ''b'' ''opb'' ''b'' | ''a'' ''opr'' ''a''--''opa'' ::= + | - | * | /--''opb'' ::= and | or--''opr'' ::= > | <--</tt>--Note that we have three groups of operators - arithmetic, booloan and-relational ones.--And now the definition of statements:--<tt>--''S'' ::= x := ''a'' | skip | ''S1''; ''S2'' | ''( S )'' | if ''b'' then ''S1'' else ''S2'' | while ''b'' do ''S''--</tt>--We probably want to parse that into some internal representation of the-language (abstract syntax tree). Therefore we need to define the data-structures for the expressions and statements.--== Data structures ==--We need to take care of boolean and arithmetic expressions and the-appropriate operators. First let's look at the boolean expressions:--<haskell>--> data BExpr = BConst Bool-> | Not BExpr-> | And BExpr BExpr-> | Greater AExpr AExpr-> deriving (Show, Eq)--</haskell>--Now we define the types for arithmetic expressions:--<haskell>--> data AExpr = Var String-> | Const Integer-> | Neg AExpr-> | Add AExpr AExpr-> deriving (Show, Eq)--</haskell>--Finally let's take care of the statements:--<haskell>--> data Stmt = Seq [Stmt]-> | Assign String AExpr-> | If BExpr Stmt Stmt-> | While BExpr Stmt-> | Skip-> deriving (Show, Eq)--</haskell>--== Lexer ==--Having all the data structures we can go on with writing the code to do actual-parsing. First of all we create the language definition using Haskell's record-syntax and the constructor <hask>emptyDef</hask> (from-<hask>Text.ParserCombinators.Parsec.Language</hask>):--<haskell>--> languageDef =-> emptyDef { Token.commentStart = "/*"-> , Token.commentEnd = "*/"-> , Token.commentLine = "//"-> , Token.identStart = letter-> , Token.identLetter = alphaNum-> , Token.reservedNames = [ "if"-> , "then"-> , "else"-> , "while"-> , "do"-> , "skip"-> , "true"-> , "false"-> , "not"-> , "and"-> , "or"-> ]-> , Token.reservedOpNames = ["+", "-", "*", "/", ":="-> , "<", ">", "and", "or", "not"-> ]-> }--</haskell>--This creates a language definition that accepts the C-style comments, requires-that the identifiers start with a letter, and end with alphanumeric-characters. Moreover there is a number of reserved names, that cannot be used-by the identifiers.--Having the above definition we can create a lexer:--<haskell>--> lexer = Token.makeTokenParser languageDef--</haskell>--<tt>lexer</tt> contains a number of lexical parsers, that we can us to parse-identifiers, reserved words/operations, etc. Now we can select/extract them in-the following way:--<haskell>--> identifier = Token.identifier lexer -- parses an identifier-> reserved = Token.reserved lexer -- parses a reserved name-> reservedOp = Token.reservedOp lexer -- parses an operator-> parens = Token.parens lexer -- parses surrounding parenthesis:-> -- parens p-> -- takes care of the parenthesis and-> -- uses p to parse what's inside them-> integer = Token.integer lexer -- parses an integer-> semi = Token.semi lexer -- parses a semicolon-> whiteSpace = Token.whiteSpace lexer -- parses whitespace--</haskell>--This isn't really necessary, but should make the code much more readable (also-this is the reason why we used the qualified import of-<hask>Text.ParserCombinators.Parsec.Token</hask>). Now we can use them to-parse the source code at the token level. One of the nice features of these-parsers is that they take care of all whitespace after the tokens.--== Main parser ==--As already mentioned a program in this language is simply a statement, so the-main parser should basically only parse a statement. But remember to take care of-initial whitespace - our parsers only get rid of whitespace after the tokens!--<haskell>--> whileParser :: Parser Stmt-> whileParser = whiteSpace >> statement--</haskell>--Now because any statement might be actually a sequence of statements separated-by semicolon, we use <hask>sepBy1</hask> to parse at least one statement. The-result is a list of statements. We also allow grouping statements by the-parenthesis, which is useful, for instance, in the <tt>while</tt> loop.--<haskell>--> statement :: Parser Stmt-> statement = parens statement-> <|> sequenceOfStmt--> sequenceOfStmt =-> do list <- (sepBy1 statement' semi)-> -- If there's only one statement return it without using Seq.-> return $ if length list == 1 then head list else Seq list--</haskell>--Now a single statement is quite simple, it's either an if conditional, a while-loop, an assignment or simply a skip statement. We use <hask><|></hask> to-express choice. So <hask>a <|> b</hask> will first try parser <hask>a</hask>-and if it fails (but without actually consuming any input) then parser-<hask>b</hask> will be used. Note: this means that the order is important.--<haskell>--> statement' :: Parser Stmt-> statement' = ifStmt-> <|> whileStmt-> <|> skipStmt-> <|> assignStmt--</haskell>--If you have a parser that might fail after consuming some input, and you still-want to try the next parser, you should look into <hask>try</hask> combinator.-For instance <hask>try p <|> q</hask> will try parsing with <hask>p</hask> and-if it fails, even after consuming the input, the <hask>q</hask> parser will be-used as if nothing has been consumed by <hask>p</hask>.--Now let's define the parsers for all the possible statements. This is quite-straightforward as we just use the parsers from the lexer and then use all the-necessary information to create appropriate data structures.--<haskell>--> ifStmt :: Parser Stmt-> ifStmt =-> do reserved "if"-> cond <- bExpression-> reserved "then"-> stmt1 <- statement-> reserved "else"-> stmt2 <- statement-> return $ If cond stmt1 stmt2--> whileStmt :: Parser Stmt-> whileStmt =-> do reserved "while"-> cond <- bExpression-> reserved "do"-> stmt <- statement-> return $ While cond stmt--> assignStmt :: Parser Stmt-> assignStmt =-> do var <- identifier-> reservedOp ":="-> expr <- aExpression-> return $ Assign var expr--> skipStmt :: Parser Stmt-> skipStmt = reserved "skip" >> return Skip--</haskell>--== Expressions ==--What's left is to parse the expressions. Fortunately Parsec provides a very-easy way to do that. Let's define the arithmetic and boolean expressions:--<haskell>--> aExpression :: Parser AExpr-> aExpression = buildExpressionParser aOperators aTerm--> bExpression :: Parser BExpr-> bExpression = buildExpressionParser bOperators bTerm--</haskell>--Now we have to define the lists with operator precedence, associativity and-what constructors to use in each case.--<haskell>--> aOperators = [ [Prefix (reservedOp "-" >> return (Neg )) ]-> , [Infix (reservedOp "+" >> return (Add )) AssocLeft]-> ]--> bOperators = [ [Prefix (reservedOp "not" >> return (Not )) ]-> , [Infix (reservedOp "and" >> return (And )) AssocLeft]-> ]--</haskell>--In case of Prefix operators it is enough to specify which one should be parsed-and what is the associated data constructor. Infix operators are defined-similarly, but it's necessary to add information about associativity. Note-that the operator precedence depends only on the order of the elements in the-list.--Finally we have to define the terms. In case of arithmetic expressions, it is-quite simple:--<haskell>--> aTerm = parens aExpression-> <|> liftM Var identifier-> <|> liftM Const integer--</haskell>--However, the term in a boolean expression is a bit more tricky. In this case,-a term can also be an expression with relational operator consisting of-arithmetic expressions.--<haskell>--> bTerm = parens bExpression-> <|> (reserved "true" >> return (BConst True ))-> <|> (reserved "false" >> return (BConst False))-> <|> rExpression--</haskell>--Therefore we have to define a parser for relational expressions:--<haskell>--> rExpression =-> do a1 <- aExpression-> op <- reservedOp ">"-> a2 <- aExpression-> return $ Greater a1 a2--</haskell>--And that's it. We have a quite simple parser able to parse a few statements and-arithmetic/boolean expressions.--== Notes ==--If you want to experiment with the parser inside ghci, these functions might be-handy:--<haskell>--> parseString :: String -> Stmt-> parseString str =-> case parse whileParser "" str of-> Left e -> error $ show e-> Right r -> r--> parseFile :: String -> IO Stmt-> parseFile file =-> do program <- readFile file-> case parse whileParser "" program of-> Left e -> print e >> fail "parse error"-> Right r -> return r--</haskell>--Now you can simply load the module in ghci and then do-<hask>ast <- parseFile "<filename>"</hask> to parse a file and get the-result if parsing was successful. If you already have a string with-the program, you can use <hask>parseString</hask>.-+Source: http://www.haskell.org/haskellwiki/Parsing_a_simple_imperative_language + +This tutorial will present how to parse a subset of a simple imperative +programming language called W<small>HILE</small> (introduced in a book +"Principles of Program Analysis" by Nielson, Nielson and Hankin). It includes +only a few statements and basic boolean/arithmetic expressions, which makes it +a nice material for a tutorial. + +== Imports == + +First let's specify the name of the module: + +<haskell> + +> module Lang where + +</haskell> + +And then import the necessary libraries: + +<haskell> + +> import System.IO +> import Control.Monad +> import Text.ParserCombinators.Parsec +> import Text.ParserCombinators.Parsec.Expr +> import Text.ParserCombinators.Parsec.Language +> import qualified Text.ParserCombinators.Parsec.Token as Token + +</haskell> + +== The language == + +The grammar for expressions is defined as follows: + +<tt> + +''a'' ::= ''x'' | ''n'' | - ''a'' | ''a'' ''opa'' ''a'' + +''b'' ::= true | false | not ''b'' | ''b'' ''opb'' ''b'' | ''a'' ''opr'' ''a'' + +''opa'' ::= + | - | * | / + +''opb'' ::= and | or + +''opr'' ::= > | < + +</tt> + +Note that we have three groups of operators - arithmetic, booloan and +relational ones. + +And now the definition of statements: + +<tt> + +''S'' ::= x := ''a'' | skip | ''S1''; ''S2'' | ''( S )'' | if ''b'' then ''S1'' else ''S2'' | while ''b'' do ''S'' + +</tt> + +We probably want to parse that into some internal representation of the +language (abstract syntax tree). Therefore we need to define the data +structures for the expressions and statements. + +== Data structures == + +We need to take care of boolean and arithmetic expressions and the +appropriate operators. First let's look at the boolean expressions: + +<haskell> + +> data BExpr = BConst Bool +> | Not BExpr +> | And BExpr BExpr +> | Greater AExpr AExpr +> deriving (Show, Eq) + +</haskell> + +Now we define the types for arithmetic expressions: + +<haskell> + +> data AExpr = Var String +> | Const Integer +> | Neg AExpr +> | Add AExpr AExpr +> deriving (Show, Eq) + +</haskell> + +Finally let's take care of the statements: + +<haskell> + +> data Stmt = Seq [Stmt] +> | Assign String AExpr +> | If BExpr Stmt Stmt +> | While BExpr Stmt +> | Skip +> deriving (Show, Eq) + +</haskell> + +== Lexer == + +Having all the data structures we can go on with writing the code to do actual +parsing. First of all we create the language definition using Haskell's record +syntax and the constructor <hask>emptyDef</hask> (from +<hask>Text.ParserCombinators.Parsec.Language</hask>): + +<haskell> + +> languageDef = +> emptyDef { Token.commentStart = "/*" +> , Token.commentEnd = "*/" +> , Token.commentLine = "//" +> , Token.identStart = letter +> , Token.identLetter = alphaNum +> , Token.reservedNames = [ "if" +> , "then" +> , "else" +> , "while" +> , "do" +> , "skip" +> , "true" +> , "false" +> , "not" +> , "and" +> , "or" +> ] +> , Token.reservedOpNames = ["+", "-", "*", "/", ":=" +> , "<", ">", "and", "or", "not" +> ] +> } + +</haskell> + +This creates a language definition that accepts the C-style comments, requires +that the identifiers start with a letter, and end with alphanumeric +characters. Moreover there is a number of reserved names, that cannot be used +by the identifiers. + +Having the above definition we can create a lexer: + +<haskell> + +> lexer = Token.makeTokenParser languageDef + +</haskell> + +<tt>lexer</tt> contains a number of lexical parsers, that we can us to parse +identifiers, reserved words/operations, etc. Now we can select/extract them in +the following way: + +<haskell> + +> identifier = Token.identifier lexer -- parses an identifier +> reserved = Token.reserved lexer -- parses a reserved name +> reservedOp = Token.reservedOp lexer -- parses an operator +> parens = Token.parens lexer -- parses surrounding parenthesis: +> -- parens p +> -- takes care of the parenthesis and +> -- uses p to parse what's inside them +> integer = Token.integer lexer -- parses an integer +> semi = Token.semi lexer -- parses a semicolon +> whiteSpace = Token.whiteSpace lexer -- parses whitespace + +</haskell> + +This isn't really necessary, but should make the code much more readable (also +this is the reason why we used the qualified import of +<hask>Text.ParserCombinators.Parsec.Token</hask>). Now we can use them to +parse the source code at the token level. One of the nice features of these +parsers is that they take care of all whitespace after the tokens. + +== Main parser == + +As already mentioned a program in this language is simply a statement, so the +main parser should basically only parse a statement. But remember to take care of +initial whitespace - our parsers only get rid of whitespace after the tokens! + +<haskell> + +> whileParser :: Parser Stmt +> whileParser = whiteSpace >> statement + +</haskell> + +Now because any statement might be actually a sequence of statements separated +by semicolon, we use <hask>sepBy1</hask> to parse at least one statement. The +result is a list of statements. We also allow grouping statements by the +parenthesis, which is useful, for instance, in the <tt>while</tt> loop. + +<haskell> + +> statement :: Parser Stmt +> statement = parens statement +> <|> sequenceOfStmt + +> sequenceOfStmt = +> do list <- (sepBy1 statement' semi) +> -- If there's only one statement return it without using Seq. +> return $ if length list == 1 then head list else Seq list + +</haskell> + +Now a single statement is quite simple, it's either an if conditional, a while +loop, an assignment or simply a skip statement. We use <hask><|></hask> to +express choice. So <hask>a <|> b</hask> will first try parser <hask>a</hask> +and if it fails (but without actually consuming any input) then parser +<hask>b</hask> will be used. Note: this means that the order is important. + +<haskell> + +> statement' :: Parser Stmt +> statement' = ifStmt +> <|> whileStmt +> <|> skipStmt +> <|> assignStmt + +</haskell> + +If you have a parser that might fail after consuming some input, and you still +want to try the next parser, you should look into <hask>try</hask> combinator. +For instance <hask>try p <|> q</hask> will try parsing with <hask>p</hask> and +if it fails, even after consuming the input, the <hask>q</hask> parser will be +used as if nothing has been consumed by <hask>p</hask>. + +Now let's define the parsers for all the possible statements. This is quite +straightforward as we just use the parsers from the lexer and then use all the +necessary information to create appropriate data structures. + +<haskell> + +> ifStmt :: Parser Stmt +> ifStmt = +> do reserved "if" +> cond <- bExpression +> reserved "then" +> stmt1 <- statement +> reserved "else" +> stmt2 <- statement +> return $ If cond stmt1 stmt2 + +> whileStmt :: Parser Stmt +> whileStmt = +> do reserved "while" +> cond <- bExpression +> reserved "do" +> stmt <- statement +> return $ While cond stmt + +> assignStmt :: Parser Stmt +> assignStmt = +> do var <- identifier +> reservedOp ":=" +> expr <- aExpression +> return $ Assign var expr + +> skipStmt :: Parser Stmt +> skipStmt = reserved "skip" >> return Skip + +</haskell> + +== Expressions == + +What's left is to parse the expressions. Fortunately Parsec provides a very +easy way to do that. Let's define the arithmetic and boolean expressions: + +<haskell> + +> aExpression :: Parser AExpr +> aExpression = buildExpressionParser aOperators aTerm + +> bExpression :: Parser BExpr +> bExpression = buildExpressionParser bOperators bTerm + +</haskell> + +Now we have to define the lists with operator precedence, associativity and +what constructors to use in each case. + +<haskell> + +> aOperators = [ [Prefix (reservedOp "-" >> return (Neg )) ] +> , [Infix (reservedOp "+" >> return (Add )) AssocLeft] +> ] + +> bOperators = [ [Prefix (reservedOp "not" >> return (Not )) ] +> , [Infix (reservedOp "and" >> return (And )) AssocLeft] +> ] + +</haskell> + +In case of Prefix operators it is enough to specify which one should be parsed +and what is the associated data constructor. Infix operators are defined +similarly, but it's necessary to add information about associativity. Note +that the operator precedence depends only on the order of the elements in the +list. + +Finally we have to define the terms. In case of arithmetic expressions, it is +quite simple: + +<haskell> + +> aTerm = parens aExpression +> <|> liftM Var identifier +> <|> liftM Const integer + +</haskell> + +However, the term in a boolean expression is a bit more tricky. In this case, +a term can also be an expression with relational operator consisting of +arithmetic expressions. + +<haskell> + +> bTerm = parens bExpression +> <|> (reserved "true" >> return (BConst True )) +> <|> (reserved "false" >> return (BConst False)) +> <|> rExpression + +</haskell> + +Therefore we have to define a parser for relational expressions: + +<haskell> + +> rExpression = +> do a1 <- aExpression +> op <- reservedOp ">" +> a2 <- aExpression +> return $ Greater a1 a2 + +</haskell> + +And that's it. We have a quite simple parser able to parse a few statements and +arithmetic/boolean expressions. + +== Notes == + +If you want to experiment with the parser inside ghci, these functions might be +handy: + +<haskell> + +> parseString :: String -> Stmt +> parseString str = +> case parse whileParser "" str of +> Left e -> error $ show e +> Right r -> r + +> parseFile :: String -> IO Stmt +> parseFile file = +> do program <- readFile file +> case parse whileParser "" program of +> Left e -> print e >> fail "parse error" +> Right r -> return r + +</haskell> + +Now you can simply load the module in ghci and then do +<hask>ast <- parseFile "<filename>"</hask> to parse a file and get the +result if parsing was successful. If you already have a string with +the program, you can use <hask>parseString</hask>. + [[Category:How to]]
examples/MultiRec.hs view
@@ -1,129 +1,120 @@-{-# LANGUAGE GADTs #-}-{-# LANGUAGE KindSignatures #-}-{-# LANGUAGE MultiParamTypeClasses #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE EmptyDataDecls #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE PolyKinds #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE StandaloneDeriving #-}--module MultiRec where--import Datatypes-import Generics.MultiRec.Any-import Generics.MultiRec.Transformations.RewriteRules as RR-import Generics.MultiRec.Transformations.ZipperState-import Generics.MultiRec.Transformations.Explicit as Ex-import Generics.MultiRec.Transformations.TH-import Generics.MultiRec.Rewriting-import Generics.MultiRec.Zipper--import Generics.MultiRec hiding (show)-import Generics.MultiRec.TH--import Control.Monad ( (>=>) )------------------------------------------------------------------------------------- Multirec representations for the example datatypes----------------------------------------------------------------------------------data TreeAST :: * -> * where- Tree :: TreeAST Tree--$(deriveAll ''TreeAST)--data ListAST :: * -> * -> * where- List :: ListAST a (List a)--$(deriveAll ''ListAST)--data XAST :: * -> * where- X :: XAST X--$(deriveAll ''XAST)--data ZigZag :: * -> * where- Zig :: ZigZag Zig- Zag :: ZigZag Zag--$(deriveAll ''ZigZag)--data AST i where- BExpr :: AST BExpr- AExpr :: AST AExpr- Stmt :: AST Stmt--$(deriveAll ''AST)------------------------------------------------------------------------------------- Rewrite rules solution----------------------------------------------------------------------------------instance RR.Transform AST---- Now we can simply do the above transformation in a nice way!-rr = RR.apply [insert (down >=> right >=> right) change] Stmt prog1 == Just prog2- where- change = rule $ \e a b -> If e a b :~> If (Not e) b a---- The same one in two steps, which illustrates that rules can be of different--- types-rr2 = RR.apply [ insert (down >=> right >=> right) swap- , insert down addNot] Stmt prog1 == Just prog2- where- swap :: Rule AST Stmt- swap = rule $ \e a b -> If e a b :~> If e b a- addNot :: Rule AST BExpr- addNot = rule $ \e -> e :~> Not e------------------------------------------------------------------------------------- Zipper with state----------------------------------------------------------------------------------zs = navigate Stmt prog1 $ do- downMonad >> rightMonad >> rightMonad- -- Swap- l <- downMonad >> rightMonad- r <- rightMonad- updateMonad (\p _ -> matchAny p l)- leftMonad- updateMonad (\p _ -> matchAny p r)- -- Add the not- leftMonad- updateMonad (\p e -> case p of- BExpr -> Just (Not e)- _ -> Nothing)------------------------------------------------------------------------------------- Explicit----------------------------------------------------------------------------------instance Ex.Transform AST---- Ordering index of AST as AExpr < BExpr < Stmt-instance OrdI AST where- indexI AExpr = 0- indexI BExpr = 1- indexI Stmt = 2--$(deriveRefRep ''AST (postfix "EH"))-deriving instance Show AExprEH-deriving instance Show BExprEH-deriving instance Show StmtEH---- Show existentials-instance Show (NiceInsert AST) where- show (NiceInsert AExpr x l) = "NiceInsert AExpr " ++ show x ++ " (" ++ show l ++ ")"- show (NiceInsert BExpr x l) = "NiceInsert BExpr " ++ show x ++ " (" ++ show l ++ ")"- show (NiceInsert Stmt x l) = "NiceInsert Stmt " ++ show x ++ " (" ++ show l ++ ")"---- Actual example-{- This prints: (note the different reference types here)- [ NiceInsert BExpr [2,0] (NotEH (RefBExpr [2,0]))- , NiceInsert Stmt [2,1] (RefStmt [2,2])- , NiceInsert Stmt [2,2] (RefStmt [2,1]) ]--}-expl1 = print $ toNiceTransformation $ diff Stmt prog1 prog2-expl2 = print $ toNiceTransformation $ diff Stmt prog3 prog4-expl3 = print $ toNiceTransformation $ diff Stmt prog5 prog6+{-# LANGUAGE GADTs #-} +{-# LANGUAGE KindSignatures #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE TypeSynonymInstances #-} +{-# LANGUAGE EmptyDataDecls #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE PolyKinds #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE RankNTypes #-} + +module MultiRec where + +import Datatypes +import Generics.MultiRec.Transformations.Main +import Generics.MultiRec.Transformations.Path + +import Generics.MultiRec hiding ( show ) +import Generics.MultiRec.TH + +import Control.Monad ( (>=>) ) + +-------------------------------------------------------------------------------- +-- Multirec representations for the example datatypes +-------------------------------------------------------------------------------- +data TreeAST :: * -> * where + Tree :: TreeAST Tree + +$(deriveAll ''TreeAST) + +data ListAST :: * -> * -> * where + List :: ListAST a (List a) + +$(deriveAll ''ListAST) + +data XAST :: * -> * where + X :: XAST X + +$(deriveAll ''XAST) + +data ZigZag :: * -> * where + Zig :: ZigZag Zig + Zag :: ZigZag Zag + +$(deriveAll ''ZigZag) + +data AST i where + BExpr :: AST BExpr + AExpr :: AST AExpr + Stmt :: AST Stmt + +$(deriveAll ''AST) + +-------------------------------------------------------------------------------- +-- Examples +-------------------------------------------------------------------------------- + +type instance Ixs AST = '[ AExpr, BExpr, Stmt ] + +deriving instance Ord AExpr +deriving instance Ord BExpr +deriving instance Ord Stmt + +test1 :: Transformation AST Stmt +test1 = diff Stmt prog1 prog2 + +-- Constructor pattern synonyms +pattern Ref' :: Path phi ix top -> HWithRef phi top ix +pattern Ref' x = HIn (Ref x) + +pattern Const' :: forall top. Integer -> HWithRef AST top AExpr +pattern Const' i = HIn (InR (R (L (Tag (R (L (C (K i)))))))) + +pattern BConst' :: forall top. Bool -> HWithRef AST top BExpr +pattern BConst' b = HIn (InR (L (Tag (L (C (K b)))))) + +pattern And' :: forall top. HWithRef AST top BExpr -> HWithRef AST top BExpr + -> HWithRef AST top BExpr +pattern And' b1 b2 = HIn (InR (L (Tag (R (R (L (C (I b1 :*: I b2)))))))) + +pattern GT' :: forall top. HWithRef AST top AExpr -> HWithRef AST top AExpr + -> HWithRef AST top BExpr +pattern GT' a1 a2 = HIn (InR (L (Tag (R (R (R (C (I a1 :*: I a2)))))))) + +test2 :: HWithRef AST top BExpr +test2 = BConst' True + +test3 :: HWithRef AST top BExpr +test3 = And' test2 test2 + +-- test6 :: HWithRef AST BExpr BExpr +-- test6 = And' (GT' (Ref' test7) (Const' 2)) (Ref' test4) + +-- Path pattern synonyms +pattern End = Empty +pattern Not_0 p = Push BExpr (CL (CTag (CR (CL (CC CId))))) p + +pattern GT_0 :: Path AST top AExpr -> Path AST top BExpr +pattern GT_0 p = Push AExpr (CL (CTag (CR (CR (CR (CC (C1 CId (I (K0 ()))))))))) p + +pattern Neg_0 :: Path AST top AExpr -> Path AST top AExpr +pattern Neg_0 p = Push AExpr (CR (CL (CTag (CR (CR (CL (CC CId))))))) p + +test4 :: Path AST BExpr BExpr +test4 = Not_0 (Not_0 End) + +test5 :: Path AST AExpr BExpr +test5 = Not_0 (GT_0 End) + +test7 :: Path AST AExpr AExpr +test7 = Neg_0 End + +-- +testPrgm = diff Stmt prog1 prog2
examples/Regular.hs view
@@ -1,212 +1,118 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE EmptyDataDecls #-}-module Regular where--import Datatypes-import Generics.Regular hiding (right)-import Generics.Regular.Transformations.Explicit as Ex-import Generics.Regular.Transformations.RewriteRules as RR-import Generics.Regular.Zipper-import Generics.Regular.Transformations.ZipperState-import Generics.Regular.Transformations.TH--import Control.Monad ( (>=>) )-import Generics.Regular.Rewriting hiding (left, right)-import Data.Maybe (fromJust)------------------------------------------------------------------------------------- Regular representations for the example datatypes------------------------------------------------------------------------------------Trees-$(deriveAll ''Tree "PFTree")-type instance PF Tree = PFTree---- Lists-$(deriveAll ''List "PFL")-type instance PF (List a) = PFL a---- Something more exotic-$(deriveAll ''X "PFX")-type instance PF X = PFX---- Example for paper (do manual instance to avoid C's)-type instance PF Expr = K String :+: K Integer :+: I :+: I :*: I--instance Regular Expr where- from (Var s) = L (K s)- from (Const i) = R (L (K i))- from (Neg e) = R (R (L (I e)))- from (Add e1 e2) = R (R (R (I e1 :*: I e2)))-- to (L (K s)) = Var s- to (R (L (K i))) = Const i- to (R (R (L (I e)))) = Neg e- to (R (R (R (I e1 :*: I e2)))) = Add e1 e2-------------------------------------------------------------------------------------- Examples for the paper------------------------------------------------------------------------------------ Some example values-expr1 :: Expr-expr1 = Add (Const 1) (Var "a")--expr2 :: Expr-expr2 = Add (Const 1) (Neg (Var "a"))--expr3 :: Expr-expr3 = Add (Var "a") (Const 1)--instance RR.Transform Expr-instance Ex.Transform Expr--instance Show (Fix (WithRef Expr)) where- show (In (Ref p)) = "Ref " ++ show p---- Insertion (expr1 => expr2)-rewriteRulesIns :: Maybe Expr-rewriteRulesIns = RR.apply [(down >=> right, rule1)] expr1- where rule1 :: Rule Expr- rule1 = rule $ \x -> x :~> Neg x--zipperStateIns :: Maybe Expr-zipperStateIns = navigate expr1 $ do- downMonad >> rightMonad- updateMonad Neg--explicitIns :: Maybe Expr-explicitIns = Ex.apply addNeg expr1- where addNeg :: Ex.Transformation Expr- addNeg = [ ([1], In . InR . R . R . L . I . In $ Ref [1]) ]---- Deletion (expr2 => expr1)--rewriteRulesDel :: Maybe Expr-rewriteRulesDel = RR.apply [(down >=> right, rule2)] expr2- where rule2 :: Rule Expr- rule2 = rule $ \x -> Neg x :~> x--zipperStateDel :: Maybe Expr-zipperStateDel = navigate expr2 $ do- r <- downMonad >> rightMonad >> downMonad- upMonad- updateMonad (const r)--explicitDel :: Maybe Expr-explicitDel = Ex.apply delNeg expr2- where delNeg :: Ex.Transformation Expr- delNeg = [ ([1], In (Ref [1,0])) ]---- Swapping (expr1 => expr3)-rewriteRulesSwap :: Maybe Expr-rewriteRulesSwap = RR.apply [(return, rule3)] expr1- where rule3 :: Rule Expr- rule3 = rule $ \l r -> Add l r :~> Add r l--zipperStateSwap :: Maybe Expr-zipperStateSwap = navigate expr1 $ do- l <- downMonad- r <- rightMonad- updateMonad (const l)- leftMonad- updateMonad (const r)--explicitSwap :: Maybe Expr-explicitSwap = Ex.apply swap' expr1- where swap' :: Ex.Transformation Expr- swap' = [ ([0], In $ Ref [1]) - , ([1], In $ Ref [0])]---- Rotation-rotate1 = Add (Var "a") (Add (Var "b") (Var "c"))-rotate2 = Add (Add (Var "a") (Var "b")) (Var "c")-rotate = diff rotate1 rotate2------------------------------------------------------------------------------------- Other RewriteRules examples----------------------------------------------------------------------------------instance RR.Transform Tree-instance RR.Transform X---- Test swapping two subtrees. Note the nice syntax!-swap :: Rule Tree-swap = rule $ \t1 t2 -> Bin t1 t2 :~> Bin t2 t1--t1 = RR.apply [(return , swap)] exTree4-t2 = RR.apply [(down , swap)] exTree4-t3 = RR.apply [(down >=> right, swap)] exTree4-t4 = RR.apply [(down >=> right, swap), (return, swap)] exTree4 -- == id---- A tricky example-ruleSwapC, ruleAddB :: Rule X-ruleSwapC = rule $ \x y -> XC x y :~> XC y x-ruleAddB = rule $ \x -> XA x :~> XA (XB x)--t6 = RR.apply [(down >=> down >=> down, ruleSwapC)] exX1-t7 = RR.apply [(down >=> down, ruleAddB)] (fromJust t6)-t8 = RR.apply [(return, ruleAddB)] (fromJust t7)-t9 = t8 == Just exX2 -- True------------------------------------------------------------------------------------- Other ZipperState examples------------------------------------------------------------------------------------ An example using a zipper with state-t5 = navigate exTree4 $- do downMonad >> downMonad- saveMonad- upMonad >> rightMonad >> downMonad >> rightMonad- saveMonad- x1 <- loadMonad- updateMonad (const x1)- upMonad >> leftMonad >> downMonad- x2 <- loadMonad- updateMonad (const x2)------------------------------------------------------------------------------------- A nicer interface for Expr, could be generated using Template Haskell----------------------------------------------------------------------------------data ExprEH- = VarEH String- | ConstEH Integer- | NegEH ExprEH- | AddEH ExprEH ExprEH- | RefEH Path- deriving Show--instance HasRef Expr where- type RefRep Expr = ExprEH- - toRef (Ref p) = RefEH p- toRef (InR (L (K s))) = VarEH s- toRef (InR (R (L (K i)))) = ConstEH i- toRef (InR (R (R (L (I e))))) = NegEH e- toRef (InR (R (R (R (I e1 :*: I e2))))) = AddEH e1 e2- - fromRef (RefEH p) = Ref p- fromRef (VarEH s) = InR (L (K s))- fromRef (ConstEH i) = InR (R (L (K i)))- fromRef (NegEH e) = InR (R (R (L (I e))))- fromRef (AddEH e1 e2) = InR (R (R (R (I e1 :*: I e2))))---$(deriveRefRep ''Tree (postfix "EH"))-deriving instance Show TreeEH---- Test-instance Ex.Transform Tree-treeSwapNice :: Maybe Tree-treeSwapNice = Ex.apply (fromNiceTransformation swap) exTree1- where swap = [([0],RefTree [1]),([1],RefTree [0])]--treeDiff :: Ex.NiceTransformation Tree-treeDiff = toNiceTransformation $ Ex.diff exTree3 exTree5--explicitInsNice :: Maybe Expr-explicitInsNice = Ex.apply (fromNiceTransformation addNeg) expr1- where addNeg :: NiceTransformation Expr- addNeg = [ ([1], NegEH (RefEH [1])) ]+{-# LANGUAGE FlexibleInstances #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE TypeFamilies #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE TypeOperators #-} +{-# LANGUAGE StandaloneDeriving #-} +{-# LANGUAGE EmptyDataDecls #-} +{-# LANGUAGE PatternSynonyms #-} + +module Regular where + +import Datatypes +import Generics.Regular hiding (right) +import Generics.Regular.Transformations.Main +import Generics.Regular.Zipper + +import Control.Monad ( (>=>) ) +import Data.Maybe (fromJust) + +-------------------------------------------------------------------------------- +-- Regular representations for the example datatypes +-------------------------------------------------------------------------------- +--Trees +$(deriveAll ''Tree "PFTree") +type instance PF Tree = PFTree + +-- Lists +$(deriveAll ''List "PFL") +type instance PF (List a) = PFL a + +-- Something more exotic +$(deriveAll ''X "PFX") +type instance PF X = PFX + +-- Example for paper +$(deriveAll ''AExpr "PFExpr") +type instance PF Expr = PFExpr + +deriving instance Ord AExpr + +-- Datatype patterns +pattern Var' x = In (InR (L (C (K x)))) +pattern Const' x = In (InR (R (L (C (K x))))) +pattern Neg' x = In (InR (R (R (L (C (I x)))))) +pattern Add' x y = In (InR (R (R (R (C (I x :*: I y)))))) + +pattern Ref' x = In (Ref x) + +-- Path patterns +pattern End = [] +pattern Neg_0 x = CR (CR (CL (CC CId))) : x +pattern Add_0 x = CR (CR (CR (CC (C1 CId (I ()))))) : x +pattern Add_1 x = CR (CR (CR (CC (C2 (I ()) CId)))) : x + +{- +type instance PF Expr = K String :+: K Integer :+: I :+: I :*: I + +instance Regular Expr where + from (Var s) = L (K s) + from (Const i) = R (L (K i)) + from (Neg e) = R (R (L (I e))) + from (Add e1 e2) = R (R (R (I e1 :*: I e2))) + + to (L (K s)) = Var s + to (R (L (K i))) = Const i + to (R (R (L (I e)))) = Neg e + to (R (R (R (I e1 :*: I e2)))) = Add e1 e2 +-} + +-------------------------------------------------------------------------------- +-- Examples for the paper +-------------------------------------------------------------------------------- +instance Transform Expr + +-- Some example values +expr1 :: Expr +expr1 = Add (Const 1) (Var "a") + +expr2 :: Expr +expr2 = Add (Const 1) (Neg (Var "a")) + +expr3 :: Expr +expr3 = Add (Var "a") (Const 1) + +explicitIns :: Maybe Expr +explicitIns = apply addNeg expr1 + where addNeg :: Transformation Expr + addNeg = diff expr1 expr2 + +-- Testing the nicer notation for paths and expressions with references +test1 :: Fix (WithRef Expr) +test1 = Neg' (Ref' test2) + +test2 :: Path Expr +test2 = Add_1 End + +test3 :: Transformation Expr +test3 = [(test2, test1)] + +test4 :: Bool +test4 = show test3 == show (diff expr1 expr2) + +-- Deletion (expr2 => expr1) +explicitDel :: Maybe Expr +explicitDel = apply delNeg expr2 + where delNeg :: Transformation Expr + delNeg = diff expr2 expr1 --[ ([1], In (Ref [1,0])) ] + +-- Swapping (expr1 => expr3) +explicitSwap :: Maybe Expr +explicitSwap = apply swap' expr1 + where swap' :: Transformation Expr + swap' = diff expr1 expr3 -- [ ([0], In $ Ref [1]), ([1], In $ Ref [0])] + +-- Rotation +rotate1 = Add (Var "a") (Add (Var "b") (Var "c")) +rotate2 = Add (Add (Var "a") (Var "b")) (Var "c") +rotate = diff rotate1 rotate2
transformations.cabal view
@@ -1,57 +1,144 @@-name: transformations-version: 0.1.1.0-synopsis: Generic representation of tree transformations-description:- This library is based on ideas described in the paper:- .- * Jeroen Bransen and Jose Pedro Magalhaes.- /Generic Representations of Tree Transformations/.- WGP'13.- <http://dreixel.net/research/pdf/grtt.pdf>--license: GPL-3-license-file: LICENSE-author: Jeroen Bransen and Jose Pedro Magalhaes-maintainer: generics@haskell.org--- copyright: -category: Language-build-type: Simple-cabal-version: >=1.8---extra-source-files: examples/Datatypes.hs- examples/Lang.lhs- examples/Regular.hs- examples/MultiRec.hs--library- exposed-modules:- -- Regular part- Generics.Regular.Zipper,- Generics.Regular.Functions.GOrd,- Generics.Regular.Transformations.Explicit,- Generics.Regular.Transformations.TH,- Generics.Regular.Transformations.RewriteRules,- Generics.Regular.Transformations.ZipperState,- - -- MultiRec implementation- Generics.MultiRec.Any,- Generics.MultiRec.Ord,- Generics.MultiRec.Transformations.ZipperState,- Generics.MultiRec.Transformations.RewriteRules,- Generics.MultiRec.Transformations.Explicit,- Generics.MultiRec.Transformations.TH,-- -- Rewriting library for MultiRec- Generics.MultiRec.HZip,- Generics.MultiRec.LR,- Generics.MultiRec.Rewriting,- Generics.MultiRec.Rewriting.Machinery,- Generics.MultiRec.Rewriting.Rules-- -- other-modules: - build-depends: base >= 4 && < 5, mtl >= 2.1,- regular >= 0.3, rewriting >= 0.2,- multirec >= 0.7.3, zipper >= 0.4.2,- parsec >= 3.1, containers >= 0.1,- template-haskell >= 2.7+name: transformations +version: 0.2.0.0 +synopsis: Generic representation of tree transformations +description: + This library is based on ideas described in the paper: + . + * Jeroen Bransen and Jose Pedro Magalhaes. + /Generic Representations of Tree Transformations/. + <http://dreixel.net/research/pdf/grtt_jfp_draft.pdf> + +license: GPL-3 +license-file: LICENSE +author: Jeroen Bransen and Jose Pedro Magalhaes +maintainer: generics@haskell.org +-- copyright: +category: Language +build-type: Simple +cabal-version: >=1.8 + +extra-source-files: README + QuickCheck.hs + examples/Datatypes.hs + examples/Expr.hs + examples/Lang.lhs + examples/Regular.hs + examples/MultiRec.hs + examples/LUA.hs + examples/LUA_project/application.lua.1 + examples/LUA_project/application.lua.2 + examples/LUA_project/application.lua.3 + examples/LUA_project/application.lua.4 + examples/LUA_project/application.lua.5 + examples/LUA_project/application.lua.6 + examples/LUA_project/application.lua.7 + examples/LUA_project/application.lua.8 + examples/LUA_project/application.lua.9 + examples/LUA_project/application.lua.10 + examples/LUA_project/application.lua.11 + examples/LUA_project/application.lua.12 + examples/LUA_project/application.lua.13 + examples/LUA_project/application.lua.14 + examples/LUA_project/application.lua.15 + examples/LUA_project/application.lua.16 + examples/LUA_project/application.lua.17 + examples/LUA_project/application.lua.18 + examples/LUA_project/application.lua.19 + examples/LUA_project/application.lua.20 + examples/LUA_project/application.lua.21 + examples/LUA_project/application.lua.22 + examples/LUA_project/application.lua.23 + examples/LUA_project/application.lua.24 + examples/LUA_project/application.lua.25 + examples/LUA_project/application.lua.26 + examples/LUA_project/application.lua.27 + examples/LUA_project/application.lua.28 + examples/LUA_project/application.lua.29 + examples/LUA_project/application.lua.30 + examples/LUA_project/application.lua.31 + examples/LUA_project/application.lua.32 + examples/LUA_project/application.lua.33 + examples/LUA_project/application.lua.34 + examples/LUA_project/application.lua.35 + examples/LUA_project/application.lua.36 + examples/LUA_project/application.lua.37 + examples/LUA_project/application.lua.38 + examples/LUA_project/application.lua.39 + examples/LUA_project/application.lua.40 + examples/LUA_project/application.lua.41 + examples/LUA_project/application.lua.42 + examples/LUA_project/application.lua.43 + examples/LUA_project/application.lua.44 + examples/LUA_project/application.lua.45 + examples/LUA_project/application.lua.46 + examples/LUA_project/application.lua.47 + examples/LUA_project/application.lua.48 + examples/LUA_project/application.lua.49 + examples/LUA_project/application.lua.50 + examples/LUA_project/application.lua.51 + examples/LUA_project/application.lua.52 + examples/LUA_project/application.lua.53 + examples/LUA_project/application.lua.54 + examples/LUA_project/application.lua.55 + examples/LUA_project/application.lua.56 + examples/LUA_project/application.lua.57 + examples/LUA_project/application.lua.58 + examples/LUA_project/application.lua.59 + examples/LUA_project/application.lua.60 + examples/LUA_project/application.lua.61 + examples/LUA_project/application.lua.62 + examples/LUA_project/application.lua.63 + examples/LUA_project/application.lua.64 + examples/LUA_project/application.lua.65 + examples/LUA_project/application.lua.66 + examples/LUA_project/application.lua.67 + examples/LUA_project/application.lua.68 + examples/LUA_project/application.lua.69 + examples/LUA_project/application.lua.70 + examples/LUA_project/application.lua.71 + examples/LUA_project/application.lua.72 + examples/LUA_project/application.lua.73 + examples/LUA_project/application.lua.74 + examples/LUA_project/application.lua.75 + examples/LUA_project/application.lua.76 + examples/LUA_project/application.lua.77 + examples/LUA_project/application.lua.78 + examples/LUA_project/application.lua.79 + examples/LUA_project/application.lua.80 + examples/LUA_project/application.lua.81 + examples/LUA_project/application.lua.82 + examples/LUA_project/application.lua.83 + examples/LUA_project/application.lua.84 + examples/LUA_project/application.lua.85 + examples/LUA_project/application.lua.86 + examples/LUA_project/application.lua.87 + examples/LUA_project/application.lua.88 + examples/LUA_project/application.lua.89 + examples/LUA_project/application.lua.90 + +library + exposed-modules: Generics.MultiRec.ShallowEq, + Generics.MultiRec.Zipper, + Generics.MultiRec.CountIs, + + Generics.MultiRec.Transformations.Main, + Generics.MultiRec.Transformations.Path, + Generics.MultiRec.Transformations.MemoTable, + Generics.MultiRec.Transformations.Children, + Generics.MultiRec.Transformations.ZipChildren + + Generics.Regular.Zipper + Generics.Regular.Functions.GOrd + Generics.Regular.Transformations.Main + + build-depends: base >= 4.7 && < 5, mtl >= 2.1, regular >= 0.3.4.4, + multirec >= 0.7.3, containers >= 0.1, + template-haskell >= 2.9 + +executable Benchmark + main-is: QuickCheck.hs + + build-depends: base >= 4.7 && < 5, mtl >= 2.1, + multirec >= 0.7.3, + parsec >= 3.1, containers >= 0.1, + criterion >= 1, QuickCheck >= 2.7