on master help sign in
Add Route code
4bdd93bJasper Van der Jeugt
src/Hakyll/Core/Route.hsnew file+71
@@ -0,0 +1,71 @@
1+-- | Once a target is compiled, the user usually wants to save it to the disk.
2+-- This is where the 'Route' type comes in; it determines where a certain target
3+-- should be written.
4+--
5+-- When a route is applied (using 'runRoute'), it either returns a 'Just'
6+-- 'FilePath' (meaning the target should be written to that file path), or
7+-- 'Nothing' (meaning this target should not be written anywhere).
8+--
9+module Hakyll.Core.Route
10+ ( Route
11+ , runRoute
12+ , idRoute
13+ , setExtension
14+ , ifMatch
15+ ) where
16+
17+import Data.Monoid (Monoid, mempty, mappend)
18+import Control.Monad (mplus)
19+import System.FilePath (replaceExtension)
20+
21+import Hakyll.Core.Identifier
22+import Hakyll.Core.Identifier.Pattern
23+
24+-- | Type used for a route
25+--
26+newtype Route = Route {unRoute :: Identifier -> Maybe FilePath}
27+
28+instance Monoid Route where
29+ mempty = Route $ const Nothing
30+ mappend (Route f) (Route g) = Route $ \id' -> f id' `mplus` g id'
31+
32+-- | Apply a route to an identifier
33+--
34+runRoute :: Route -> Identifier -> Maybe FilePath
35+runRoute = unRoute
36+
37+-- | A route that uses the identifier as filepath. For example, the target with
38+-- ID @foo\/bar@ will be written to the file @foo\/bar@.
39+--
40+idRoute :: Route
41+idRoute = Route $ Just . toFilePath
42+
43+-- | Set (or replace) the extension of a route.
44+--
45+-- Example:
46+--
47+-- > runRoute (setExtension "html") "foo/bar"
48+--
49+-- Result:
50+--
51+-- > Just "foo/bar.html"
52+--
53+-- Example:
54+--
55+-- > runRoute (setExtension "html") "posts/the-art-of-trolling.markdown"
56+--
57+-- Result:
58+--
59+-- > Just "posts/the-art-of-trolling.html"
60+--
61+setExtension :: String -> Route
62+setExtension exension = Route $ fmap (flip replaceExtension exension)
63+ . unRoute idRoute
64+
65+-- | Modify a route: apply the route if the identifier matches the given
66+-- pattern, fail otherwise.
67+--
68+ifMatch :: Pattern -> Route -> Route
69+ifMatch pattern (Route route) = Route $ \id' ->
70+ if doesMatch pattern id' then route id'
71+ else Nothing
tests/Hakyll/Core/Route/Tests.hsnew file+25
@@ -0,0 +1,25 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+module Hakyll.Core.Route.Tests
3+ ( tests
4+ ) where
5+
6+import Test.Framework
7+import Test.Framework.Providers.HUnit
8+import Test.HUnit hiding (Test)
9+
10+import Hakyll.Core.Route
11+
12+tests :: [Test]
13+tests = zipWith testCase names matchCases
14+ where
15+ names = map (\n -> "runRoute [" ++ show n ++ "]") [1 :: Int ..]
16+
17+-- | Collection of simple cases
18+--
19+matchCases :: [Assertion]
20+matchCases =
21+ [ Just "foo.html" @=? runRoute (setExtension "html") "foo"
22+ , Just "foo.html" @=? runRoute (setExtension ".html") "foo"
23+ , Just "foo.html" @=? runRoute (setExtension "html") "foo.markdown"
24+ , Just "foo.html" @=? runRoute (setExtension ".html") "foo.markdown"
25+ ]
tests/TestSuite.hs+3
@@ -4,6 +4,7 @@ import Test.Framework (defaultMain, testGroup)
4
4
5import qualified Hakyll.Core.DirectedGraph.Tests
5import qualified Hakyll.Core.DirectedGraph.Tests
6import qualified Hakyll.Core.Identifier.Tests
6import qualified Hakyll.Core.Identifier.Tests
7+import qualified Hakyll.Core.Route.Tests
7
8
8main :: IO ()
9main :: IO ()
9main = defaultMain
10main = defaultMain
@@ -11,4 +12,6 @@ main = defaultMain
11 Hakyll.Core.DirectedGraph.Tests.tests
12 Hakyll.Core.DirectedGraph.Tests.tests
12 , testGroup "Hakyll.Core.Identifier.Tests"
13 , testGroup "Hakyll.Core.Identifier.Tests"
13 Hakyll.Core.Identifier.Tests.tests
14 Hakyll.Core.Identifier.Tests.tests
15+ , testGroup "Hakyll.Core.Route.Tests"
16+ Hakyll.Core.Route.Tests.tests
14 ]
17 ]