-- | Module containing various functions to manipulate contexts. module Text.Hakyll.Context ( Context , ContextManipulation , renderValue , changeValue , renderDate , changeExtension ) where import qualified Data.Map as M import Data.Map (Map) import System.Locale (defaultTimeLocale) import System.FilePath (takeFileName, addExtension, dropExtension) import Data.Time.Format (parseTime, formatTime) import Data.Time.Clock (UTCTime) import Data.Maybe (fromMaybe) import Text.Hakyll.Regex (substituteRegex) -- | Type for a context. type Context = Map String String -- | Type for context manipulating functions. type ContextManipulation = Context -> Context -- | Do something with a value in a @Context@, but keep the old value as well. -- This is probably the most common function to construct a -- @ContextManipulation@. renderValue :: String -- ^ Key of which the value should be copied. -> String -- ^ Key the value should be copied to. -> (String -> String) -- ^ Function to apply on the value. -> ContextManipulation renderValue src dst f context = case M.lookup src context of Nothing -> context (Just value) -> M.insert dst (f value) context -- | Change a value in a @Context@. -- -- > import Data.Char (toUpper) -- > changeValue "title" (map toUpper) -- -- Will put the title in UPPERCASE. changeValue :: String -- ^ Key to change. -> (String -> String) -- ^ Function to apply on the value. -> ContextManipulation changeValue key = renderValue key key -- | When the context has a key called @path@ in a @yyyy-mm-dd-title.extension@ -- format (default for pages), this function can render the date. -- -- > renderDate "date" "%B %e, %Y" "Date unknown" -- -- Will render something like @January 32, 2010@. renderDate :: String -- ^ Key in which the rendered date should be placed. -> String -- ^ Format to use on the date. -> String -- ^ Default value when the date cannot be parsed. -> ContextManipulation renderDate key format defaultValue context = M.insert key value context where value = fromMaybe defaultValue pretty pretty = do filePath <- M.lookup "path" context let dateString = substituteRegex "^([0-9]*-[0-9]*-[0-9]*).*" "\\1" (takeFileName filePath) time <- parseTime defaultTimeLocale "%Y-%m-%d" dateString :: Maybe UTCTime return $ formatTime defaultTimeLocale format time -- | Change the extension of a file. This is only needed when you want to -- render, for example, mardown to @.php@ files instead of @.html@ files. -- -- > renderChainWith (changeExtension "php") -- > ["templates/default.html"] -- > (createPagePath "test.markdown") -- -- Will render to @test.php@ instead of @test.html@. changeExtension :: String -- ^ Extension to change to. -> ContextManipulation changeExtension extension = changeValue "url" changeExtension' where changeExtension' = flip addExtension extension . dropExtension