heterocephalus 1.0.4.0 → 1.0.5.0
raw patch · 7 files changed
+140/−43 lines, 7 filesdep +mtldep +transformersPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: mtl, transformers
API changes (from Hackage documentation)
+ Text.Heterocephalus: ParseOptions :: Char -> Char -> ParseOptions
+ Text.Heterocephalus: [parseOptionsControlPrefix] :: ParseOptions -> Char
+ Text.Heterocephalus: [parseOptionsVariablePrefix] :: ParseOptions -> Char
+ Text.Heterocephalus: [parseOptions] :: HeterocephalusSetting -> ParseOptions
+ Text.Heterocephalus: createParseOptions :: Char -> Char -> ParseOptions
+ Text.Heterocephalus: data ParseOptions
+ Text.Heterocephalus: defaultParseOptions :: ParseOptions
- Text.Heterocephalus: HeterocephalusSetting :: Q Exp -> HeterocephalusSetting
+ Text.Heterocephalus: HeterocephalusSetting :: Q Exp -> ParseOptions -> HeterocephalusSetting
Files
- CHANGELOG.md +11/−0
- README.md +2/−2
- heterocephalus.cabal +4/−1
- src/Text/Heterocephalus.hs +24/−3
- src/Text/Heterocephalus/Parse.hs +9/−6
- src/Text/Heterocephalus/Parse/Control.hs +57/−31
- src/Text/Heterocephalus/Parse/Option.hs +33/−0
CHANGELOG.md view
@@ -1,6 +1,17 @@ Change Log ========== +Version 1.0.5.0 (2017-06-05)+----------------++### New features++* Add settings to be able to change the character used to deliminate control statements #18++### Document updates++* Fixed small spelling/grammars on readme #19+ Version 1.0.4.0 (2017-02-07) ----------------
README.md view
@@ -26,7 +26,7 @@ There are many Haskell template engines today. [Shakespeare](http://hackage.haskell.org/package/shakespeare) is great because it checks template variables at compile time. Using Shakespeare, it's not-possible to for the template file to cause a runtime-error.+possible for the template file to cause a runtime-error. Shakespeare provides its own original ways of writing HTML ([Hamlet](https://hackage.haskell.org/package/shakespeare/docs/Text-Hamlet.html)),@@ -53,7 +53,7 @@ [long time to compile](https://github.com/blueimpact/kucipong/pull/7) with GHC >= 7.10. -Hetercephalus fills this missing niche. It gives you variable interpolation+Heterocephalus fills this missing niche. It gives you variable interpolation along with control statements that can be used with any markup language. Its compile times are reasonable.
heterocephalus.cabal view
@@ -1,5 +1,5 @@ name: heterocephalus-version: 1.0.4.0+version: 1.0.5.0 synopsis: A type-safe template engine for working with popular front end development tools description: Recent front end development tools and languages are growing fast and have@@ -33,15 +33,18 @@ , Text.Heterocephalus.Parse , Text.Heterocephalus.Parse.Control , Text.Heterocephalus.Parse.Doc+ , Text.Heterocephalus.Parse.Option build-depends: base >= 4.7 && < 5 , blaze-html >= 0.8 && < 0.10 , blaze-markup >= 0.7 && < 0.9 , containers >= 0.5 && < 0.6 , dlist >= 0.7.1.1+ , mtl , parsec >= 3.1 && < 3.2 , shakespeare >= 2.0 && < 2.1 , template-haskell >= 2.7 && < 3 , text >= 1.2 && < 1.3+ , transformers ghc-options: -Wall default-language: Haskell2010
src/Text/Heterocephalus.hs view
@@ -39,6 +39,9 @@ , HeterocephalusSetting(..) , textSetting , htmlSetting+ , ParseOptions(..)+ , defaultParseOptions+ , createParseOptions , DefaultScope , compile , compileWith@@ -85,7 +88,8 @@ (Deref, Ident(..), Scope, derefToExp, readUtf8File) import Text.Heterocephalus.Parse- (Doc(..), Content(..), docFromString)+ (Doc(..), Content(..), ParseOptions(..), createParseOptions,+ defaultParseOptions, docFromString) {- $setup >>> :set -XTemplateHaskell -XQuasiQuotes@@ -332,6 +336,20 @@ contents <- fmap TL.unpack $ qRunIO $ readUtf8File fp compileFromStringWithDefault scope' set contents +{-| Same as 'compileFile', but just compile the 'String' given.++ >>> let as = ["<a>", "b"]+ >>> let template = "sample %{ forall a <- as }key: #{a}, %{ endforall }"+ >>> renderMarkup $(compileFromString textSetting template)+ "sample key: <a>, key: b, "++ >>> let as = ["<a>", "b"]+ >>> let options = createParseOptions '|' '?'+ >>> let setting = textSetting { parseOptions = options }+ >>> let template = "sample |{ forall a <- as }key: ?{a}, |{ endforall }"+ >>> renderMarkup $(compileFromString setting template)+ "sample key: <a>, key: b, "+-} compileFromString :: HeterocephalusSetting -> String -> Q Exp compileFromString = compileFromStringWithDefault [] @@ -341,7 +359,7 @@ forM defScope $ \(ident, qexp) -> (ident, ) <$> overwriteScope ident qexp owScope' <- forM owScope $ \(ident, qexp) -> (ident, ) <$> qexp- docsToExp set (owScope' ++ defScope') $ docFromString s+ docsToExp set (owScope' ++ defScope') $ docFromString (parseOptions set) s where (defDList, owDList) = runScopeM scopeM defScope = DList.toList defDList@@ -351,7 +369,7 @@ compileFromStringWithDefault scope' set s = do scope <- forM scope' $ \(ident, qexp) -> (ident, ) <$> overwriteScope ident qexp- docsToExp set scope $ docFromString s+ docsToExp set scope $ docFromString (parseOptions set) s overwriteScope :: Ident -> Q Exp -> Q Exp overwriteScope (Ident str) qexp = do@@ -366,6 +384,7 @@ { escapeExp :: Q Exp -- ^ Template variables are passed to 'escapeExp' in the output. This allows -- things like escaping HTML entities. (See 'htmlSetting'.)+ , parseOptions :: ParseOptions } {-| A setting that escapes template variables for Html@@ -375,6 +394,7 @@ htmlSetting :: HeterocephalusSetting htmlSetting = HeterocephalusSetting { escapeExp = [|toHtml|]+ , parseOptions = defaultParseOptions } {-| A setting that DOES NOT escape template variables.@@ -384,6 +404,7 @@ textSetting :: HeterocephalusSetting textSetting = HeterocephalusSetting { escapeExp = [|preEscapedToMarkup|]+ , parseOptions = defaultParseOptions } type DefaultScope = [(Ident, Q Exp)]
src/Text/Heterocephalus/Parse.hs view
@@ -9,21 +9,24 @@ ( module Text.Heterocephalus.Parse , module Text.Heterocephalus.Parse.Control , module Text.Heterocephalus.Parse.Doc+ , module Text.Heterocephalus.Parse.Option ) where import Text.Heterocephalus.Parse.Control (Content(..), parseLineControl) import Text.Heterocephalus.Parse.Doc (Doc(..), parseDocFromControls)+import Text.Heterocephalus.Parse.Option+ (ParseOptions(..), createParseOptions, defaultParseOptions) -docFromString :: String -> [Doc]-docFromString s =- case parseDoc s of+docFromString :: ParseOptions -> String -> [Doc]+docFromString opts s =+ case parseDoc opts s of Left s' -> error s' Right d -> d -parseDoc :: String -> Either String [Doc]-parseDoc s = do- controls <- parseLineControl s+parseDoc :: ParseOptions -> String -> Either String [Doc]+parseDoc opts s = do+ controls <- parseLineControl opts s case parseDocFromControls controls of Left parseError -> Left $ show parseError Right docs -> Right docs
src/Text/Heterocephalus/Parse/Control.hs view
@@ -12,18 +12,23 @@ import Control.Applicative ((<$>), (*>), (<*), pure) #endif import Control.Monad (guard, void)+import Control.Monad.Reader (Reader, runReaderT) import Data.Char (isUpper) import Data.Data (Data) import Data.Functor (($>))+import Data.Functor.Identity (runIdentity) import Data.Typeable (Typeable) import Text.Parsec- (Parsec, (<?>), (<|>), alphaNum, between, char, choice, eof, many,- many1, manyTill, noneOf, oneOf, option, optional, parse, sepBy,- skipMany, spaces, string, try)+ (Parsec, ParsecT, (<?>), (<|>), alphaNum, between, char, choice,+ eof, many, many1, manyTill, mkPT, noneOf, oneOf, option, optional,+ runParsecT, runParserT, sepBy, skipMany, spaces, string,+ try) import Text.Shakespeare.Base- (Ident(Ident), Deref, parseDeref, parseHash)+ (Ident(Ident), Deref, parseDeref, parseVar) import Text.Hamlet.Parse+import Text.Heterocephalus.Parse.Option+ (ParseOptions, getControlPrefix, getVariablePrefix) data Control = ControlForall Deref Binding@@ -42,52 +47,62 @@ | ContentVar Deref deriving (Data, Eq, Read, Show, Typeable) -type UserParser = Parsec String ()+type UserParser = ParsecT String () (Reader ParseOptions) -parseLineControl :: String -> Either String [Control]-parseLineControl s =- case parse lineControl s s of- Left e -> Left $ show e- Right x -> Right x+parseLineControl :: ParseOptions -> String -> Either String [Control]+parseLineControl opts s =+ let readerT = runParserT lineControl () "" s+ res = runIdentity $ runReaderT readerT opts+ in case res of+ Left e -> Left $ show e+ Right x -> Right x lineControl :: UserParser [Control] lineControl = manyTill control $ try eof >> return () control :: UserParser Control-control = controlHash <|> controlPercent <|> controlReg+control = noControlVariable <|> controlStatement <|> noControlRaw where- controlPercent :: UserParser Control- controlPercent = do- x <- parsePercent+ controlStatement :: UserParser Control+ controlStatement = do+ x <- parseControlStatement case x of Left str -> return (NoControl $ ContentRaw str) Right ctrl -> return ctrl - controlHash :: UserParser Control- controlHash = do- x <- parseHash+ noControlVariable :: UserParser Control+ noControlVariable = do+ variablePrefix <- getVariablePrefix+ x <- identityToReader $ parseVar variablePrefix return . NoControl $ case x of Left str -> ContentRaw str Right deref -> ContentVar deref - controlReg :: UserParser Control- controlReg = (NoControl . ContentRaw) <$> many (noneOf "#%")+ noControlRaw :: UserParser Control+ noControlRaw = do+ controlPrefix <- getControlPrefix+ variablePrefix <- getVariablePrefix+ (NoControl . ContentRaw) <$>+ many (noneOf [controlPrefix, variablePrefix]) -parsePercent :: UserParser (Either String Control)-parsePercent = do- a <- parseControl '%'+parseControlStatement :: UserParser (Either String Control)+parseControlStatement = do+ a <- parseControl optional eol return a where eol :: UserParser () eol = void (char '\n') <|> void (string "\r\n") -parseControl :: Char -> UserParser (Either String Control)-parseControl c = do- _ <- char c- let escape = char '\\' $> Left [c]- escape <|> (Right <$> parseControlBetweenBrackets) <|> return (Left [c])+parseControl :: UserParser (Either String Control)+parseControl = do+ controlPrefix <- getControlPrefix+ void $ char controlPrefix+ let escape = char '\\' $> Left [controlPrefix]+ escape <|>+ (Right <$> parseControlBetweenBrackets) <|>+ return (Left [controlPrefix]) parseControlBetweenBrackets :: UserParser Control parseControlBetweenBrackets =@@ -112,10 +127,14 @@ parseEndForall = string "endforall" $> ControlEndForall parseIf :: UserParser Control- parseIf = string "if" *> spaces *> fmap ControlIf parseDeref+ parseIf =+ string "if" *> spaces *> fmap ControlIf (identityToReader parseDeref) parseElseIf :: UserParser Control- parseElseIf = string "elseif" *> spaces *> fmap ControlElseIf parseDeref+ parseElseIf =+ string "elseif" *>+ spaces *>+ fmap ControlElseIf (identityToReader parseDeref) parseElse :: UserParser Control parseElse = string "else" $> ControlElse@@ -124,7 +143,10 @@ parseEndIf = string "endif" $> ControlEndIf parseCase :: UserParser Control- parseCase = string "case" *> spaces *> fmap ControlCase parseDeref+ parseCase =+ string "case" *>+ spaces *>+ fmap ControlCase (identityToReader parseDeref) parseCaseOf :: UserParser Control parseCaseOf = string "of" *> spaces *> fmap ControlCaseOf identPattern@@ -138,7 +160,7 @@ spaces _ <- string "<-" spaces- x <- parseDeref+ x <- identityToReader parseDeref _ <- spaceTabs return (x, y) @@ -319,3 +341,7 @@ listpat :: UserParser Binding listpat = BindList <$> identPattern `sepBy` comma++identityToReader :: Parsec String () a -> UserParser a+identityToReader p =+ mkPT $ pure . fmap (pure . runIdentity) . runIdentity . runParsecT p
+ src/Text/Heterocephalus/Parse/Option.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE FlexibleContexts #-}++module Text.Heterocephalus.Parse.Option where++import Control.Monad.Reader (MonadReader, reader)++data ParseOptions = ParseOptions+ { parseOptionsControlPrefix :: Char+ , parseOptionsVariablePrefix :: Char+ }++-- | Default set of parser options.+--+-- Sets 'parseOptionsControlPrefix' to @\'%\'@ and+-- 'parseOptionsVariablePrefix' to @\'#\'@.+defaultParseOptions :: ParseOptions+defaultParseOptions = createParseOptions '%' '#'++createParseOptions+ :: Char -- ^ The control prefix.+ -> Char -- ^ The variable prefix.+ -> ParseOptions+createParseOptions controlPrefix varPrefix = ParseOptions+ { parseOptionsControlPrefix = controlPrefix+ , parseOptionsVariablePrefix = varPrefix+ }++getControlPrefix :: MonadReader ParseOptions m => m Char+getControlPrefix = reader parseOptionsControlPrefix++getVariablePrefix :: MonadReader ParseOptions m => m Char+getVariablePrefix = reader parseOptionsVariablePrefix