on 5dba607 help sign in
hakyll/src/Hakyll/Core/Identifier.hs
98 lines 3.2 kB history raw
1-- | An identifier is a type used to uniquely identify a resource, target...
2--
3-- One can think of an identifier as something similar to a file path. An
4-- identifier is a path as well, with the different elements in the path
5-- separated by @/@ characters. Examples of identifiers are:
6--
7-- * @posts/foo.markdown@
8--
9-- * @index@
10--
11-- * @error/404@
12--
13-- The most important difference between an 'Identifier' and a file path is that
14-- the identifier for an item is not necesserily the file path.
15--
16-- For example, we could have an @index@ identifier, generated by Hakyll. The
17-- actual file path would be @index.html@, but we identify it using @index@.
18--
19-- @posts/foo.markdown@ could be an identifier of an item that is rendered to
20-- @posts/foo.html@. In this case, the identifier is the name of the source
21-- file of the page.
22--
23-- An `Identifier` carries the type of the value it identifies. This basically
24-- means that an @Identifier (Page String)@ refers to a page.
25--
26-- It is a phantom type parameter, meaning you can safely change this if you
27-- know what you are doing. You can change the type using the 'castIdentifier'
28-- function.
29--
30-- If the @a@ type is not known, Hakyll traditionally uses @Identifier ()@.
31--
32{-# LANGUAGE GeneralizedNewtypeDeriving, DeriveDataTypeable #-}
33module Hakyll.Core.Identifier
34 ( Identifier (..)
35 , castIdentifier
36 , parseIdentifier
37 , toFilePath
38 , setGroup
39 ) where
41import Control.Arrow (second)
42import Control.Applicative ((<$>), (<*>))
43import Control.Monad (mplus)
44import Data.Monoid (Monoid, mempty, mappend)
45import Data.List (intercalate)
47import Data.Binary (Binary, get, put)
48import GHC.Exts (IsString, fromString)
49import Data.Typeable (Typeable)
51-- | An identifier used to uniquely identify a value
52--
53data Identifier a = Identifier
54 { identifierGroup :: Maybe String
55 , identifierPath :: String
56 } deriving (Eq, Ord, Typeable)
58instance Monoid (Identifier a) where
59 mempty = Identifier Nothing ""
60 Identifier g1 p1 `mappend` Identifier g2 p2 =
61 Identifier (g1 `mplus` g2) (p1 `mappend` p2)
63instance Binary (Identifier a) where
64 put (Identifier g p) = put g >> put p
65 get = Identifier <$> get <*> get
67instance Show (Identifier a) where
68 show i@(Identifier Nothing _) = toFilePath i
69 show i@(Identifier (Just g) _) = toFilePath i ++ " (" ++ g ++ ")"
71instance IsString (Identifier a) where
72 fromString = parseIdentifier
74-- | Discard the phantom type parameter of an identifier
75--
76castIdentifier :: Identifier a -> Identifier b
77castIdentifier (Identifier g p) = Identifier g p
78{-# INLINE castIdentifier #-}
80-- | Parse an identifier from a string
81--
82parseIdentifier :: String -> Identifier a
83parseIdentifier = Identifier Nothing
84 . intercalate "/" . filter (not . null) . split'
85 where
86 split' [] = [[]]
87 split' str = let (pre, post) = second (drop 1) $ break (== '/') str
88 in pre : split' post
90-- | Convert an identifier to a relative 'FilePath'
91--
92toFilePath :: Identifier a -> FilePath
93toFilePath = identifierPath
95-- | Set the identifier group for some identifier
96--
97setGroup :: Maybe String -> Identifier a -> Identifier a
98setGroup g (Identifier _ p) = Identifier g p