on master help sign in
Fix feeds
commit6b5c299ec945cdfea2dbf2df0922f8753588b729 authorJasper Van der Jeugt <m@jaspervdj.be> dateSun 18 Nov 2012, 23:27 (14 years ago) parentf6c4fb8
6 files changed+103−91
hakyll.cabal+1−1 src/Hakyll.hs+2−2 src/Hakyll/Core/Compiler.hs+1 src/Hakyll/Core/Compiler/Require.hs+10−3 src/Hakyll/Web/Feed.hs+79−84 src/Hakyll/Web/Template/Context.hs+10−1
hakyll.cabal+1−1
@@ -110,7 +110,7 @@ Library
110110 Hakyll.Core.Writable.CopyFile
111111 Hakyll.Main
112112 Hakyll.Web.CompressCss
113− -- Hakyll.Web.Feed
113+ Hakyll.Web.Feed
114114 Hakyll.Web.Page
115115 -- Hakyll.Web.Page.List
116116 Hakyll.Web.Page.Metadata
src/Hakyll.hs+2−2
@@ -20,7 +20,7 @@ module Hakyll
2020 , module Hakyll.Core.Writable.CopyFile
2121 , module Hakyll.Main
2222 , module Hakyll.Web.CompressCss
23− -- , module Hakyll.Web.Feed
23+ , module Hakyll.Web.Feed
2424 , module Hakyll.Web.Page
2525 -- , module Hakyll.Web.Page.List
2626 , module Hakyll.Web.Pandoc
@@ -53,7 +53,7 @@ import Hakyll.Core.Writable
5353import Hakyll.Core.Writable.CopyFile
5454import Hakyll.Main
5555import Hakyll.Web.CompressCss
56−-- import Hakyll.Web.Feed
56+import Hakyll.Web.Feed
5757import Hakyll.Web.Page
5858-- import Hakyll.Web.Page.List
5959import Hakyll.Web.Pandoc
src/Hakyll/Core/Compiler.hs+1
@@ -12,6 +12,7 @@ module Hakyll.Core.Compiler
1212 , getResourceLBS
1313 , getResourceWith
1414 , require
15+ , requireBody
1516 , requireAll
1617 , cached
1718 , unsafeCompiler
src/Hakyll/Core/Compiler/Require.hs+10−3
@@ -2,6 +2,7 @@
22module Hakyll.Core.Compiler.Require
33 ( save
44 , require
5+ , requireBody
56 , requireAll
67 ) where
78
@@ -17,6 +18,7 @@ import Hakyll.Core.Compiler.Internal
1718import Hakyll.Core.Dependencies
1819import Hakyll.Core.Identifier
1920import Hakyll.Core.Identifier.Pattern
21+import Hakyll.Core.Item
2022import Hakyll.Core.Store (Store)
2123import qualified Hakyll.Core.Store as Store
2224
@@ -27,7 +29,7 @@ save store identifier x = Store.set store (key identifier) x
2729
2830
2931--------------------------------------------------------------------------------
30−require :: (Binary a, Typeable a) => Identifier -> Compiler a
32+require :: (Binary a, Typeable a) => Identifier -> Compiler (Item a)
3133require id' = do
3234 store <- compilerStore <$> compilerAsk
3335
@@ -37,7 +39,7 @@ require id' = do
3739 case result of
3840 Store.NotFound -> compilerThrow notFound
3941 Store.WrongType e r -> compilerThrow $ wrongType e r
40− Store.Found x -> return x
42+ Store.Found x -> return $ Item id' x
4143 where
4244 notFound =
4345 "Hakyll.Core.Compiler.Require.require: " ++ show id' ++ " was " ++
@@ -50,7 +52,12 @@ require id' = do
5052
5153
5254--------------------------------------------------------------------------------
53−requireAll :: (Binary a, Typeable a) => Pattern -> Compiler [a]
55+requireBody :: (Binary a, Typeable a) => Identifier -> Compiler a
56+requireBody = fmap itemBody . require
57+
58+
59+--------------------------------------------------------------------------------
60+requireAll :: (Binary a, Typeable a) => Pattern -> Compiler [Item a]
5461requireAll pattern = do
5562 universe <- compilerUniverse <$> compilerAsk
5663 let matching = filterMatches pattern universe
src/Hakyll/Web/Feed.hs+79−84
@@ -1,11 +1,11 @@
1−-- TODO: port
1+--------------------------------------------------------------------------------
22-- | A Module that allows easy rendering of RSS feeds.
33--
44-- The main rendering functions (@renderRss@, @renderAtom@) all assume that
55-- you pass the list of items so that the most recent entry in the feed is the
66-- first item in the list.
77--
8−-- Also note that the pages should have (at least) the following fields to
8+-- Also note that the context should have (at least) the following fields to
99-- produce a correct feed:
1010--
1111-- - @$title$@: Title of the item
@@ -15,29 +15,33 @@
1515-- - @$url$@: URL to the item - this is usually set automatically.
1616--
1717-- In addition, the posts should be named according to the rules for
18−-- 'Hakyll.Page.Metadata.renderDateField'.
19−--
18+-- 'Hakyll.Web.Template.Context.dateField'
2019module Hakyll.Web.Feed
2120 ( FeedConfiguration (..)
2221 , renderRss
2322 , renderAtom
2423 ) where
2524
26−import Prelude hiding (id)
27−import Control.Category (id)
28−import Control.Arrow ((>>>), arr, (&&&))
29−import Control.Monad ((<=<))
30−import Data.Maybe (fromMaybe, listToMaybe)
3125
32−import Hakyll.Core.Compiler
33−import Hakyll.Web.Page
34−import Hakyll.Web.Page.Metadata
35−import Hakyll.Web.Template
36−import Hakyll.Web.Template.Read.Hakyll (readTemplate)
37−import Hakyll.Web.Urls
26+--------------------------------------------------------------------------------
27+import Control.Monad (forM, (<=<))
28+import Data.Monoid (mconcat)
29+
30+
31+--------------------------------------------------------------------------------
32+import Hakyll.Core.Compiler
33+import Hakyll.Core.Compiler.Internal
34+import Hakyll.Core.Item
35+import Hakyll.Web.Template
36+import Hakyll.Web.Template.Context
37+import Hakyll.Web.Template.Read.Hakyll (readTemplate)
3838
39−import Paths_hakyll
4039
40+--------------------------------------------------------------------------------
41+import Paths_hakyll
42+
43+
44+--------------------------------------------------------------------------------
4145-- | This is a data structure to keep the configuration of a feed.
4246data FeedConfiguration = FeedConfiguration
4347 { -- | Title of the feed.
@@ -52,83 +56,74 @@ data FeedConfiguration = FeedConfiguration
5256 feedRoot :: String
5357 } deriving (Show, Eq)
5458
55−-- | This is an auxiliary function to create a listing that is, in fact, a feed.
56−-- The items should be sorted on date. The @$updated@ field should be set for
57−-- each item.
58−--
59−createFeed :: Template -- ^ Feed template
60− -> Template -- ^ Item template
61− -> String -- ^ URL of the feed
62− -> FeedConfiguration -- ^ Feed configuration
63− -> [Page String] -- ^ Items to include
64− -> String -- ^ Resulting feed
65−createFeed feedTemplate itemTemplate url configuration items =
66− pageBody $ applyTemplateToPage feedTemplate
67− $ trySetField "updated" updated
68− $ trySetField "title" (feedTitle configuration)
69− $ trySetField "description" (feedDescription configuration)
70− $ trySetField "authorName" (feedAuthorName configuration)
71− $ trySetField "authorEmail" (feedAuthorEmail configuration)
72− $ trySetField "root" (feedRoot configuration)
73− $ trySetField "url" url
74− $ fromBody body
75− where
76− -- Preprocess items
77− items' = flip map items $ applyTemplateToPage itemTemplate
78− . trySetField "root" (feedRoot configuration)
79−
80− -- Body: concatenated items
81− body = concat $ map pageBody items'
82−
83− -- Take the first updated, which should be the most recent
84− updated = fromMaybe "Unknown" $ do
85− p <- listToMaybe items
86− return $ getField "updated" p
87−
8859
60+--------------------------------------------------------------------------------
8961-- | Abstract function to render any feed.
90−--
91−renderFeed :: FilePath -- ^ Feed template
92− -> FilePath -- ^ Item template
93− -> FeedConfiguration -- ^ Feed configuration
94− -> Compiler [Page String] String -- ^ Feed compiler
95−renderFeed feedTemplate itemTemplate configuration =
96− id &&& getRoute >>> renderFeed'
97− where
98− -- Arrow rendering the feed from the items and the URL
99− renderFeed' = unsafeCompiler $ \(items, url) -> do
100− feedTemplate' <- loadTemplate feedTemplate
101− itemTemplate' <- loadTemplate itemTemplate
102− let url' = toUrl $ fromMaybe noUrl url
103− return $ createFeed feedTemplate' itemTemplate' url' configuration items
62+renderFeed :: FilePath -- ^ Feed template
63+ -> FilePath -- ^ Item template
64+ -> FeedConfiguration -- ^ Feed configuration
65+ -> Context String -- ^ Context for the items
66+ -> [Item String] -- ^ Input items
67+ -> Compiler (Item String) -- ^ Resulting item
68+renderFeed feedPath itemPath config itemContext items = do
69+ feedTpl <- compilerUnsafeIO $ loadTemplate feedPath
70+ itemTpl <- compilerUnsafeIO $ loadTemplate itemPath
10471
72+ items' <- forM items $ applyTemplate itemTpl itemContext'
73+ body <- makeItem $ concat $ map itemBody items'
74+ applyTemplate feedTpl feedContext body
75+ where
10576 -- Auxiliary: load a template from a datafile
10677 loadTemplate = fmap readTemplate . readFile <=< getDataFileName
10778
108− -- URL is required to have a valid field
109− noUrl = error "Hakyll.Web.Feed.renderFeed: no route specified"
79+ itemContext' = mconcat
80+ [ constField "root" (feedRoot config)
81+ , itemContext
82+ ]
83+
84+ feedContext = mconcat
85+ [ bodyField "body"
86+ , constField "title" (feedTitle config)
87+ , constField "description" (feedDescription config)
88+ , constField "authorName" (feedAuthorName config)
89+ , constField "authorEmail" (feedAuthorEmail config)
90+ , constField "root" (feedRoot config)
91+ , urlField "url"
92+ , updatedField
93+ , missingField
94+ ]
95+
96+ -- Take the first "updated" field from all items -- this should be the most
97+ -- recent.
98+ updatedField = field "updated" $ \_ -> case items of
99+ [] -> return "Unknown"
100+ (x : _) -> unContext itemContext' "updated" x
110101
102+
103+--------------------------------------------------------------------------------
111104-- | Render an RSS feed with a number of items.
112−--
113−renderRss :: FeedConfiguration -- ^ Feed configuration
114− -> Compiler [Page String] String -- ^ Feed compiler
115−renderRss configuration = arr (map (addUpdated . renderDate))
116− >>> renderFeed "templates/rss.xml" "templates/rss-item.xml" configuration
117− where
118− renderDate = renderDateField "published" "%a, %d %b %Y %H:%M:%S UT"
119− "No date found."
105+renderRss :: FeedConfiguration -- ^ Feed configuration
106+ -> Context String -- ^ Item context
107+ -> [Item String] -- ^ Feed items
108+ -> Compiler (Item String) -- ^ Resulting feed
109+renderRss config context = renderFeed
110+ "templates/rss.xml" "templates/rss-item.xml" config
111+ (makeItemContext "%a, %d %b %Y %H:%M:%S UT" context)
120112
113+
114+--------------------------------------------------------------------------------
121115-- | Render an Atom feed with a number of items.
122−--
123−renderAtom :: FeedConfiguration -- ^ Feed configuration
124− -> Compiler [Page String] String -- ^ Feed compiler
125−renderAtom configuration = arr (map (addUpdated . renderDate))
126− >>> renderFeed "templates/atom.xml" "templates/atom-item.xml" configuration
127− where
128− renderDate = renderDateField "published" "%Y-%m-%dT%H:%M:%SZ"
129− "No date found."
116+renderAtom :: FeedConfiguration -- ^ Feed configuration
117+ -> Context String -- ^ Item context
118+ -> [Item String] -- ^ Feed items
119+ -> Compiler (Item String) -- ^ Resulting feed
120+renderAtom config context = renderFeed
121+ "templates/atom.xml" "templates/atom-item.xml" config
122+ (makeItemContext "%Y-%m-%dT%H:%M:%SZ" context)
130123
124+
125+--------------------------------------------------------------------------------
131126-- | Copies @$updated$@ from @$published$@ if it is not already set.
132−--
133−addUpdated :: Page a -> Page a
134−addUpdated page = trySetField "updated" (getField "published" page) page
127+makeItemContext :: String -> Context a -> Context a
128+makeItemContext fmt context = mconcat
129+ [dateField "published" fmt, context, dateField "updated" fmt]
src/Hakyll/Web/Template/Context.hs+10−1
@@ -3,6 +3,7 @@ module Hakyll.Web.Template.Context
33 ( Context (..)
44 , mapContext
55 , field
6+ , constField
67
78 , defaultContext
89 , bodyField
@@ -15,6 +16,7 @@ module Hakyll.Web.Template.Context
1516 , dateFieldWith
1617 , modificationTimeField
1718 , modificationTimeFieldWith
19+ , missingField
1820 ) where
1921
2022
@@ -63,6 +65,11 @@ field :: String -> (Item a -> Compiler String) -> Context a
6365field key value = Context $ \k i -> if k == key then value i else empty
6466
6567
68+--------------------------------------------------------------------------------
69+constField :: String -> String -> Context a
70+constField key = field key . const . return
71+
72+
6673--------------------------------------------------------------------------------
6774defaultContext :: Context String
6875defaultContext =
@@ -194,4 +201,6 @@ modificationTimeFieldWith locale key fmt = field key $ \i -> do
194201
195202--------------------------------------------------------------------------------
196203missingField :: Context a
197−missingField = Context $ \k _ -> return $ "$" ++ k ++ "$"
204+missingField = Context $ \k i -> compilerThrow $
205+ "Missing field $" ++ k ++ "$ in context for item " ++
206+ show (itemIdentifier i)