module Text.StringTemplate.Helpers ( directoryGroupSafer , renderTemplateGroup , render1 ) where import Text.StringTemplate hiding (directoryGroup) import System.Directory import System.FilePath import Control.Applicative import Data.List (find) import Data.Char -- Chooses a template from an STGroup, or errors if not found. -- Renders that template uses attrs, and gives the string. -- if you don't clean and a template k/v pair is repeated, it appears twice. -- Possibly this should be a fix inside StringTemplate. Tell sclv? -- what is the expected StringTemplate behavior according to the original program? --clean = nubBy (\(a1,b1) (a2,b2) -> a1 == a2) . sortBy (\(a1,b1) (a2,b2) -> a1 `compare` a2) -- but then again, why should a key be repeated twice? maybe showing a repeat is a good thing -- as it indicates buggy behavior -- The ToSElem type is probably either String or [String] --renderTemplateGroup :: (ToSElem a) => STGroup String -> [(String, a)] -> [Char] -> String renderTemplateGroup :: STGroup String -> [(String, String)] -> [Char] -> String renderTemplateGroup gr attrs tmpl = maybe ( "template not found: " ++ tmpl ) ( toString . setManyAttribSafer attrs ) ( getStringTemplate tmpl gr ) directoryGroupSafer :: (Stringable a) => FilePath -> IO (STGroup a) directoryGroupSafer path = groupStringTemplates <$> (fmap <$> zip . (map dropExtension) <*> mapM (newSTMP <$$> (readFile . (path ))) =<< mapM checkTmplName =<< return . filter (not . or . map (=='#') {-naughty emacs backup character-} ) . filter ( (".st" ==) . takeExtension ) =<< getDirectoryContents path) where checkTmplName t = if ( badTmplVarName . takeBaseName ) t then fail $ "safeDirectoryGroup, bad template name: " ++ t else return t setManyAttribSafer attrs st = let mbFoundbadattr = find badTmplVarName . map fst $ attrs in maybe (setManyAttrib attrs st) (\mbA -> newSTMP . ("setManyAttribSafer, bad template atr: "++) $ mbA) mbFoundbadattr (<$$>) :: (Functor f1, Functor f) => (a -> b) -> f (f1 a) -> f (f1 b) (<$$>) x y = ((<$>) . (<$>)) x y badTmplVarName t = or . map (not . isAlpha) $ t render1 :: [(String,String)] -> String -> String render1 attribs tmpl = render . setManyAttrib attribs . newSTMP $ tmpl