ginger 0.5.2.1 → 0.5.3.0
raw patch · 5 files changed
+117/−4 lines, 5 filesdep −wrytePVP ok
version bump matches the API change (PVP)
Dependencies removed: wryte
API changes (from Hackage documentation)
+ Text.Ginger.GVal: marshalFunction :: (Functor m, Functor n) => (forall a. m a -> n a) -> (forall a. n a -> m a) -> Function m -> Function n
+ Text.Ginger.GVal: marshalGValEx :: (Functor m, Functor n) => (forall a. m a -> n a) -> (forall a. n a -> m a) -> GVal m -> GVal n
+ Text.Ginger.Run: hoistContext :: Monad m => (h -> t) -> (t -> h) -> GingerContext m h -> GingerContext m t
+ Text.Ginger.Run: hoistNewlines :: (h -> t) -> (t -> h) -> Newlines h -> Newlines t
+ Text.Ginger.Run: hoistRun :: Monad m => (h -> t) -> (t -> h) -> Run m h a -> Run m t a
+ Text.Ginger.Run: hoistRunState :: Monad m => (h -> t) -> (t -> h) -> RunState m h -> RunState m t
+ Text.Ginger.Run.VM: withEncoder :: (ContextEncodable h, Monad m) => (GVal (Run m h) -> h) -> Run m h a -> Run m h a
Files
- ginger.cabal +1/−3
- src/Text/Ginger/GVal.hs +35/−0
- src/Text/Ginger/Run.hs +5/−0
- src/Text/Ginger/Run/Type.hs +69/−0
- src/Text/Ginger/Run/VM.hs +7/−1
ginger.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: ginger-version: 0.5.2.1+version: 0.5.3.0 synopsis: An implementation of the Jinja2 template language in Haskell description: Ginger is Jinja, minus the most blatant pythonisms. Wants to be feature complete, but isn't quite there yet.@@ -50,7 +50,6 @@ , unordered-containers >= 0.2.5 , utf8-string , vector- , wryte hs-source-dirs: src default-language: Haskell2010 @@ -66,7 +65,6 @@ , text , transformers , unordered-containers >= 0.2.5- , wryte test-suite tests type: exitcode-stdio-1.0
src/Text/Ginger/GVal.hs view
@@ -2,6 +2,7 @@ {-#LANGUAGE MultiParamTypeClasses #-} {-#LANGUAGE FlexibleInstances #-} {-#LANGUAGE ScopedTypeVariables #-}+{-#LANGUAGE RankNTypes #-} -- | GVal is a generic unitype value, representing the kind of values that -- Ginger can understand.@@ -34,6 +35,7 @@ , not , fst, snd , Monad+ , Functor ) import qualified Prelude import Data.Maybe ( fromMaybe, catMaybes, isJust, mapMaybe )@@ -127,6 +129,39 @@ , length = length g , asJSON = asJSON g }++-- | Marshal a GVal between carrier monads.+-- Unlike 'marshalGVal', 'asFunction' information is retained by hoisting+-- them using the provided hoisting functions. For 'Run' monads, which is+-- what 'GVal' is typically used with, the 'hoistRun' function can be used+-- to construct suitable hoisting functions.+marshalGValEx :: (Functor m, Functor n)+ => (forall a. m a -> n a)+ -> (forall a. n a -> m a)+ -> GVal m+ -> GVal n+marshalGValEx hoist unhoist g =+ GVal+ { asList = fmap (marshalGValEx hoist unhoist) <$> asList g+ , asDictItems = fmap (\items -> [(k, marshalGValEx hoist unhoist v) | (k, v) <- items]) (asDictItems g)+ , asLookup = fmap (fmap (marshalGValEx hoist unhoist) .) (asLookup g)+ , asHtml = asHtml g+ , asText = asText g+ , asBoolean = asBoolean g+ , asNumber = asNumber g+ , asFunction = marshalFunction hoist unhoist <$> asFunction g+ , isNull = isNull g+ , length = length g+ , asJSON = asJSON g+ }++marshalFunction :: (Functor m, Functor n) => (forall a. m a -> n a) -> (forall a. n a -> m a) -> Function m -> Function n+-- [(Maybe Text, GVal m)] -> m (GVal m)+marshalFunction hoist unhoist f args =+ let args' = [ (name, marshalGValEx unhoist hoist value)+ | (name, value) <- args+ ]+ in marshalGValEx hoist unhoist <$> hoist (f args') -- | Convenience wrapper around 'asDictItems' to represent a 'GVal' as a -- 'HashMap'.
src/Text/Ginger/Run.hs view
@@ -46,6 +46,11 @@ , Run, liftRun, liftRun2 -- * Helper functions for interpreting argument lists , extractArgs, extractArgsT, extractArgsL, extractArgsDefL+-- * Hoisting+, hoistContext+, hoistRun+, hoistNewlines+, hoistRunState ) where
src/Text/Ginger/Run/Type.hs view
@@ -24,6 +24,11 @@ -- * The Newlines type -- | Required for handling indentation , Newlines (..)+-- * Hoisting+, hoistContext+, hoistRun+, hoistNewlines+, hoistRunState ) where @@ -89,6 +94,29 @@ , contextNewlines :: Maybe (Newlines h) } +-- | Hoist a context onto a different output type.+-- @hoistContext fwd rev context@ returns a context over a different+-- output type, applying the @fwd@ and @rev@ projections to convert+-- between the original and desired output types.+hoistContext :: Monad m => (h -> t) -> (t -> h) -> GingerContext m h -> GingerContext m t+hoistContext fwd rev c =+ GingerContext+ { contextLookup = \varName ->+ marshalGValEx+ (hoistRun fwd rev)+ (hoistRun rev fwd) <$>+ hoistRun fwd rev (contextLookup c varName)+ , contextWrite = \val ->+ hoistRun fwd rev (contextWrite c $ rev val)+ , contextEncode = \gval ->+ fwd .+ contextEncode c .+ marshalGValEx (hoistRun rev fwd) (hoistRun fwd rev) $+ gval+ , contextNewlines =+ hoistNewlines fwd rev <$> contextNewlines c+ }+ contextWriteEncoded :: GingerContext m h -> GVal (Run m h) -> Run m h () contextWriteEncoded context = contextWrite context . contextEncode context@@ -213,6 +241,18 @@ , endsWithNewline :: h -> Bool } +-- | Hoist a 'Newlines' onto a different output type.+-- You don't normally need to use this directly; see 'hoistRun' and/or+-- 'hoistContext'.+hoistNewlines :: (h -> t) -> (t -> h) -> Newlines h -> Newlines t+hoistNewlines fwd rev n =+ Newlines+ { splitLines = List.map fwd . splitLines n . rev+ , joinLines = fwd . joinLines n . List.map rev+ , stripIndent = fwd . stripIndent n . rev+ , endsWithNewline = endsWithNewline n . rev+ }+ textNewlines :: Newlines Text textNewlines = Newlines@@ -249,6 +289,20 @@ , rsAtLineStart :: Bool -- is the next output position the first column } +-- | Hoist a 'RunState' onto a different output type.+-- You don't normally need to use this directly; see 'hoistRun' and/or+-- 'hoistContext'.+hoistRunState :: Monad m => (h -> t) -> (t -> h) -> RunState m h -> RunState m t+hoistRunState fwd rev rs =+ RunState+ { rsScope = marshalGValEx (hoistRun fwd rev) (hoistRun rev fwd) <$> rsScope rs+ , rsCapture = fwd $ rsCapture rs+ , rsCurrentTemplate = rsCurrentTemplate rs+ , rsCurrentBlockName = rsCurrentBlockName rs+ , rsIndentation = fmap fwd <$> rsIndentation rs+ , rsAtLineStart = rsAtLineStart rs+ }+ -- | Internal type alias for our template-runner monad stack. type Run m h = StateT (RunState m h) (ReaderT (GingerContext m h) m) @@ -259,3 +313,18 @@ -- | Lift a function from the host monad @m@ into the 'Run' monad. liftRun2 :: Monad m => (a -> m b) -> a -> Run m h b liftRun2 f x = liftRun $ f x++-- | Hoist a 'Run' action onto a different output type.+-- @hoistRun fwd rev action@ hoists the @action@ from @Run m h a@ to+-- @Run m t a@, applying @fwd@ and @rev@ to convert between the output+-- types.+hoistRun :: Monad m => (h -> t) -> (t -> h) -> Run m h a -> Run m t a+hoistRun fwd rev action = do+ contextT <- ask+ let contextH = hoistContext rev fwd contextT+ stateT <- get+ let stateH = hoistRunState rev fwd stateT+ (x, stateH') <- lift . lift $ runReaderT (runStateT action stateH) contextH+ let stateT' = hoistRunState fwd rev stateH'+ put stateT'+ return x
src/Text/Ginger/Run/VM.hs view
@@ -7,7 +7,7 @@ import Text.Ginger.GVal import Data.Monoid ( (<>) ) import Control.Monad.State (MonadState (..), get, gets, modify)-import Control.Monad.Reader (asks)+import Control.Monad.Reader (asks, local) import qualified Data.HashMap.Strict as HashMap import Data.HashMap.Strict (HashMap) @@ -28,6 +28,12 @@ r <- a modify (\s -> s { rsScope = scope }) return r++-- | Override the encoder used for converting 'GVal's to the output type.+-- This can be used for things like temporarily disabling HTML encoding.+withEncoder :: (ContextEncodable h, Monad m) => (GVal (Run m h) -> h) -> Run m h a -> Run m h a+withEncoder encoder =+ local (\context -> context { contextEncode = encode }) setVar :: Monad m => VarName -> GVal (Run m h) -> Run m h () setVar name val = do