File: Classes.hs

package info (click to toggle)
haskell-hstringtemplate 0.8.8-5
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 164 kB
  • sloc: haskell: 999; makefile: 2
file content (144 lines) | stat: -rw-r--r-- 5,048 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
{-# LANGUAGE ExistentialQuantification, FlexibleInstances, StandaloneDeriving, GeneralizedNewtypeDeriving, TypeSynonymInstances #-}
{-# OPTIONS_HADDOCK not-home #-}
module Text.StringTemplate.Classes
    (SElem(..), StringTemplateShows(..), ToSElem(..), SMap, STShow(..),
     StFirst(..), Stringable(..), stShowsToSE
    ) where
import qualified Data.Map as M
import Data.List
import Data.Monoid
import qualified Blaze.ByteString.Builder as BB
import qualified Blaze.ByteString.Builder.Char.Utf8 as BB
import qualified Data.ByteString.Char8 as B
import qualified Data.ByteString.Lazy.Char8 as LB
--import qualified Data.ByteString.Lazy.Builder as DBB
import qualified Data.Semigroup as SG
import qualified Data.Text as T
import qualified Data.Text.Encoding as T
import qualified Data.Text.Lazy as LT
import qualified Data.Text.Lazy.Builder as TB
import qualified Data.Text.Lazy.Encoding as LT
import qualified Text.PrettyPrint.HughesPJ as PP

newtype StFirst a = StFirst { stGetFirst :: Maybe a }
        deriving (Eq, Ord, Read, Show)
instance SG.Semigroup (StFirst a) where
        r@(StFirst (Just _)) <> _ = r
        StFirst Nothing      <> r = r
instance Monoid (StFirst a) where
        mempty  = StFirst Nothing
        mappend = (SG.<>)

instance Functor StFirst where
    fmap f = StFirst . fmap f . stGetFirst

type SMap a = M.Map String (SElem a)

data SElem a = STR  String
             | BS   LB.ByteString
             | TXT  LT.Text
             | STSH STShow
             | SM (SMap a)
             | LI [SElem a]
             | SBLE a
             | SNAT a
             | SNull

-- | The ToSElem class should be instantiated for all types that can be
-- inserted as attributes into a StringTemplate.
class ToSElem a where
    toSElem :: Stringable b => a -> SElem b
    toSElemList :: Stringable b => [a] -> SElem b
    toSElemList = LI . map toSElem

-- | The StringTemplateShows class should be instantiated for all types that are
-- directly displayed in a StringTemplate, but take an optional format string. Each such type must have an appropriate ToSElem method defined as well.
class (Show a) => StringTemplateShows a where
    -- | Defaults to 'show'.
    stringTemplateShow :: a -> String
    stringTemplateShow = show
    -- | Defaults to  @ \ _ a -> stringTemplateShow a @
    stringTemplateFormattedShow :: String -> a -> String
    stringTemplateFormattedShow = flip $ const . stringTemplateShow

-- | This method should be used to create ToSElem instances for
-- types defining a custom formatted show function.
stShowsToSE :: (StringTemplateShows a, Stringable b) => a -> SElem b
stShowsToSE = STSH . STShow

data STShow = forall a.(StringTemplateShows a) => STShow a

-- | The Stringable class should be instantiated with care.
-- Generally, the provided instances should be enough for anything.
class Monoid a => Stringable a where
    stFromString :: String -> a
    stFromByteString :: LB.ByteString -> a
    stFromByteString = stFromText . LT.decodeUtf8
    stFromText :: LT.Text -> a
    stFromText = stFromString . LT.unpack
    stToString :: a -> String
    -- | Defaults to  @ mconcatMap m k = foldr (mappend . k) mempty m @
    mconcatMap :: [b] -> (b -> a) -> a
    mconcatMap m k = foldr (mappend . k) mempty m
    -- | Defaults to  @ (mconcat .) . intersperse @
    mintercalate :: a -> [a] -> a
    mintercalate = (mconcat .) . intersperse
    -- | Defaults to  @  mlabel x y = mconcat [x, stFromString "[", y, stFromString "]"] @
    mlabel :: a -> a -> a
    mlabel x y = mconcat [x, stFromString "[", y, stFromString "]"]

instance Stringable String where
    stFromString = id
    stToString = id

instance Stringable PP.Doc where
    stFromString = PP.text
    stToString = PP.render
    mconcatMap m k = PP.fcat . map k $ m
    mintercalate = (PP.fcat .) . PP.punctuate
    mlabel x y = x PP.$$ PP.nest 1 y

instance Stringable B.ByteString where
    stFromString = B.pack
    stFromByteString = B.concat . LB.toChunks
    stToString = B.unpack

instance Stringable LB.ByteString where
    stFromString = LB.pack
    stFromByteString = id
    stToString = LB.unpack

instance Stringable T.Text where
    stFromString = T.pack
    stFromByteString = T.decodeUtf8 . B.concat . LB.toChunks
    stFromText = LT.toStrict
    stToString = T.unpack

instance Stringable LT.Text where
    stFromString = LT.pack
    stFromByteString = LT.decodeUtf8
    stFromText = id
    stToString = LT.unpack

instance Stringable BB.Builder where
    stFromString = BB.fromString
    stFromByteString = BB.fromLazyByteString
    stToString = LB.unpack . BB.toLazyByteString

{-
instance Stringable LBB.Builder where
    stFromString = stringUtf8
    stFromByteString = LBB.lazyByteString
    stToString = LB.unpack . LBB.toLazyByteString
-}

instance Stringable TB.Builder where
    stFromString = TB.fromString
    stFromText = TB.fromLazyText
    stToString = LT.unpack . TB.toLazyText


--add dlist instance
instance Stringable (Endo String) where
    stFromString = Endo . (++)
    stToString = ($ []) . appEndo