mustache-0.1.0.0: src/lib/Text/Mustache/Types.hs
{-|
Module : $Header$
Description : Types and conversions
Copyright : (c) Justus Adam, 2015
License : LGPL-3
Maintainer : development@justusadam.com
Stability : experimental
Portability : POSIX
-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE UnicodeSyntax #-}
{-# LANGUAGE FlexibleContexts #-}
module Text.Mustache.Types
(
-- * Types for the Parser / Template
MustacheAST
, MustacheTemplate(..)
, MustacheNode(..)
-- * Types for the Substitution / Data
, Value(..)
-- ** Converting
, object
, (~>), (~=), (~~>), (~~=)
, ToMustache, toMustache, toMustacheText, mFromJSON
-- ** Representation
, Array, Object
, Context(..)
) where
import qualified Data.Aeson as Aeson
import Data.Functor ((<$>))
import Data.HashMap.Strict as HM
import Data.Scientific
import Data.Text
import qualified Data.Text.Lazy as LT
import qualified Data.Vector as V
import Conversion
import Conversion.Text ()
-- | Abstract syntax tree for a mustache template
type MustacheAST = [MustacheNode Text]
-- | Basic values composing the AST
data MustacheNode a
= MustacheText a
| MustacheSection [Text] MustacheAST
| MustacheInvertedSection [Text] MustacheAST
| MustacheVariable Bool [Text]
| MustachePartial FilePath
deriving (Show, Eq)
type Array = V.Vector Value
type Object = HM.HashMap Text Value
type KeyValuePair = (Text, Value)
-- | Representation of stateful context for the substitution process
data Context a = Context [a] a
-- | Internal value AST
data Value
= Object Object
| Array Array
| Number Scientific
| String Text
| Lambda (Context Value → MustacheAST → Either String MustacheAST)
| Bool Bool
| Null
instance Show Value where
show (Lambda _) = "Lambda Context Value → MustacheAST → Either String MustacheAST"
show (Object o) = show o
show (Array a) = show a
show (String s) = show s
show (Number n) = show n
show (Bool b) = show b
show Null = "null"
-- | Conversion class
class ToMustache a where
toMustache ∷ a → Value
instance ToMustache [Char] where
toMustache = String . pack
instance ToMustache Bool where
toMustache = Bool
instance ToMustache Char where
toMustache = String . pack . return
instance ToMustache () where
toMustache = const Null
instance ToMustache Text where
toMustache = String
instance ToMustache LT.Text where
toMustache = String . LT.toStrict
instance ToMustache Scientific where
toMustache = Number
instance ToMustache Value where
toMustache = id
instance ToMustache m ⇒ ToMustache [m] where
toMustache = Array . V.fromList . fmap toMustache
instance ToMustache m ⇒ ToMustache (V.Vector m) where
toMustache = Array . fmap toMustache
instance ToMustache m ⇒ ToMustache (HM.HashMap Text m) where
toMustache = Object . fmap toMustache
instance ToMustache (Context Value → MustacheAST → Either String MustacheAST) where
toMustache = Lambda
instance ToMustache (Context Value → MustacheAST → Either String Text) where
toMustache f = Lambda wrapper
where wrapper c lAST = return . MustacheText <$> f c lAST
instance ToMustache (Context Value → MustacheAST → MustacheAST) where
toMustache f = Lambda wrapper
where wrapper c = Right . f c
instance ToMustache (Context Value → MustacheAST → Text) where
toMustache f = Lambda wrapper
where wrapper c = Right . return . MustacheText . f c
instance ToMustache (Context Value → MustacheAST → String) where
toMustache f = toMustache wrapper
where wrapper c = pack . f c
instance ToMustache (MustacheAST → Either String MustacheAST) where
toMustache f = Lambda $ const f
instance ToMustache (MustacheAST → Either String Text) where
toMustache f = Lambda wrapper
where wrapper _ = fmap (return . MustacheText) . f
instance ToMustache (MustacheAST → Either String String) where
toMustache f = toMustache (fmap pack . f)
instance ToMustache (MustacheAST → Text) where
toMustache f = toMustache (Right . f ∷ MustacheAST -> Either String Text)
instance ToMustache (MustacheAST → String) where
toMustache f = toMustache (pack . f)
instance ToMustache Aeson.Value where
toMustache (Aeson.Object o) = Object $ fmap toMustache o
toMustache (Aeson.Array a) = Array $ fmap toMustache a
toMustache (Aeson.Number n) = Number n
toMustache (Aeson.String s) = String s
toMustache (Aeson.Bool b) = Bool b
toMustache (Aeson.Null) = Null
-- | Convenience function for creating Object values.
--
-- This function is supposed to be used in conjuction with the '~>' and '~=' operators.
--
-- ==== __Examples__
--
-- @
-- data Address = Address { ... }
--
-- instance Address ToJSON where
-- ...
--
-- data Person = Person { name :: String, address :: Address }
--
-- instance ToMustache Person where
-- toMustache (Person { name, address }) = object
-- [ "name" ~> name
-- , "address" ~= address
-- ]
-- @
--
-- Here we can see that we can use the '~>' operator for values that have themselves
-- a 'ToMustache' instance, or alternatively if they lack such an instance but provide
-- an instance for the 'ToJSON' typeclass we can use the '~=' operator.
object ∷ [(Text, Value)] → Value
object = Object . HM.fromList
-- | Map keys to values that provide a 'ToMustache' instance
--
-- Recommended in conjunction with the `OverloadedStrings` extension.
(~>) ∷ ToMustache m ⇒ Text → m → KeyValuePair
(~>) t = (t, ) . toMustache
-- | Map keys to values that provide a 'ToJSON' instance
--
-- Recommended in conjunction with the `OverloadedStrings` extension.
(~=) ∷ Aeson.ToJSON j ⇒ Text → j → KeyValuePair
(~=) t = (t ~>) . Aeson.toJSON
-- | Conceptually similar to '~>' but uses arbitrary String-likes as keys.
(~~>) ∷ (Conversion t Text, ToMustache m) ⇒ t → m → KeyValuePair
(~~>) = (~>) . convert
-- | Conceptually similar to '~=' but uses arbitrary String-likes as keys.
(~~=) ∷ (Conversion t Text, Aeson.ToJSON j) ⇒ t → j → KeyValuePair
(~~=) = (~=) . convert
-- | Converts arbitrary String-likes to Values
toMustacheText ∷ Conversion t Text ⇒ t → Value
toMustacheText = String . convert
-- | Converts a value that can be represented as JSON to a Value.
mFromJSON ∷ Aeson.ToJSON j ⇒ j → Value
mFromJSON = toMustache . Aeson.toJSON
{-|
A compiled Template with metadata.
-}
data MustacheTemplate = MustacheTemplate { name ∷ String
, ast ∷ MustacheAST
, partials ∷ [MustacheTemplate]
} deriving (Show)