on master help sign in
Some more changes for the 0.3 release.
commit533f2c3b60ef3d3629543045fa308a82ebdcb089 authorJasper Van der Jeugt <jaspervdj@gmail.com> dateMon 28 Dec 2009, 18:21 (17 years ago) parent4561887
2 files changed+16−215
README.markdown+4−211 hakyll.cabal+12−4
README.markdown+4−211
@@ -9,216 +9,9 @@ reference.
99
1010## Installation
1111
12− cabal install hakyll
12+cabal install hakyll
1313
14−## Configuration
14+## Tutorial and information
1515
16−Inspired by [xmonad](http://xmonad.org), a small Haskell program is used as
17−configuration file. In this file, you give instructions on how the site should
18−be generated. In the rest of this document, we will examine a small example.
19−
20−This is our directory layout:
21−
22− |-- _cache
23− |-- _site
24− |-- favicon.ico
25− |-- hakyll.hs
26− |-- images
27− | `-- foo.png
28− |-- templates
29− | |-- default.html
30− | `-- sample.html
31− `-- text.markdown
32−
33−The `_cache` and `_site` directories will be automatically created by hakyll.
34−
35−## Static files
36−
37−Static files can be rendered using the `static` function. This function
38−ensures the files will copied when you compile the site. Hakyll is smart enough
39−to know when files have changed, and will check the modification time of a file
40−before copying.
41−
42−For convenience reasons, there is also a `staticDirectory` function, which works
43−recursively.
44−
45− main = do
46− static "favicon.ico"
47− staticDirectory "images"
48− staticDirectory "css"
49−
50−## Pages
51−
52−Pages can be written in html, markdown, LaTeX, and basically anything pandoc
53−supports. They can also contain metadata, which are always key-value mappings.
54−
55− ---
56− author: Jasper Van der Jeugt
57− title: A sample markdown post
58− ---
59− # A sample markdown post
60−
61− This is a sample markdown post. It supports pandoc extensions
62− like code highlighting. For example:
63−
64− ~~~~{.haskell}
65− main = putStrLn "Hello World!"
66− ~~~~
67−
68−Metadata is always placed in the header of a file, and is delimited by a `---`
69−string. The metadata can only contain simple key-value pairs. We can now read
70−in this page using the `Text.Hakyll.Page.readPage` function. This will return a
71−`Page`, which is actually just a `Map String ByteString`. In this example, the
72−map would consist of the following key-value pairs:
73−
74−- `author`: `Jasper Van der Jeugt`
75−- `title`: `A sample markdown post`
76−- `body`: The rest of the file (rendered to html).
77−- `url`: `text.html` (the original filename was `text.markdown`, the extension
78− was changed to html).
79−
80−## Templates
81−
82−In hakyll, there is a strict separation between pages and templates. Templates,
83−for example, cannot contain metadata.
84−
85− <h2> $title </h2>
86− by <strong> $author </strong>
87−
88− $body
89−
90−Templates are rendered using the Haskell `Text.Template` library. This means
91−that in your template, you can use `$identifier`, and it will be replaced by
92−the value of `identifier`.
93−
94−With this template we could, for example, render the file we saw in the
95−previous section. It would go like this:
96−
97− page <- readPage "text.markdown"
98− rendered <- render "templates/sample.html" page
99− writePage rendered
100−
101−This reads in `text.markdown`, renders it and writes it to the site destination
102−(`_site/text.html`). The result of a `render` action is an `IO Page`, the
103−metadata will be copied from the original page, and the body will be replaced by
104−the rendering result. This means we can combine rendering actions. Given another
105−template `templates/default.html`:
106− <html>
107− <head>
108− <title> $title </title>
109− </head>
110− <body>
111− $body
112− </body>
113− </html>
114−
115−We can now combine the rendering actions (I use `>>=` notation here):
116− readPage "text.markdown" >>=
117− render "templates/sample.html" >>=
118− render "templates/default.html" >>=
119− writePage
120−
121−Jolly good fun and all that, but you can imagine that when we render over nine
122−thousand posts, our generator will be busy for a while. That's why we have the
123−`depends` function. It takes a url and a list of dependencies as arguments, and
124−an IO action. The trick is that this IO action will only be executed if any of
125−the dependencies is newer than the url given. In our example, we would write:
126−
127− depends "text.html" ["text.markdown", "templates/sample.html", "templates/default.html"]
128− (readPage "text.markdown" >>= render "templates/sample.html" >>=
129− render "templates/default.html" >>= writePage)
130−
131−Not exactly the prettiest code I've ever seen. Because rendering a page with a
132−number of templates is very common, there's a `renderChain` function to do this
133−for us. The above can be replaced by
134−
135− renderChain ["templates/sample.html", "templates/default.html"] $
136− createPagePath "text.markdown"
137−
138−The `renderChain` function will automatically check dependencies and write the
139−page. In fact, it is recommended that you __always__ use this, even when there's
140−only one template in the chain.
141−
142−## More advanced things
143−
144−Sometimes, you want to create a `Page` from scratch, without reading from a
145−file. There are functions to do that for you, and I suggest you read the
146−documentation of `Text.Hakyll.Page`. As a more advanced example, I will explain
147−the RSS system I wrote for my website.
148−
149− |-- generate.hs
150− |-- posts
151− | `-- 2009-12-02-a-first-post.markdown
152− `-- templates
153− |-- rss.xml
154− `-- rssitem.xml
155−
156−Our post contains some metadata:
157−
158− ---
159− title: A first post
160− date: December 2, 2009
161− about: A post describing the why and the how of the technical setup of this blog.
162− ---
163−
164− # A first post
165−
166− A first post describing the technical setup of this blog, for that is
167−
168−The `templates/rssitem.xml` file is a template for rendering one post to an rss
169−item:
170−
171− <item>
172− <title> $title </title>
173− <link>http://jaspervdj.be/$url</link>
174− <description> $about </description>
175− </item>
176−
177−Now a template for rendering the whole rss feed, `templates/rss.xml`:
178−
179− <?xml version="1.0"?>
180− <rss version="2.0">
181− <channel>
182− <title>jaspervdj - a personal blog</title>
183− <link>http://jaspervdj.be/</link>
184− <description>Personal blog of jaspervdj</description>
185− $items
186− </channel>
187− </rss>
188−
189−Alright, let's get coding. We first want a list of all posts, sorted so the most
190−recent entries are first in the list.
191−
192− postPaths <- liftM (L.reverse . L.sort) $ getRecursiveContents "posts"
193−
194−Note that this sorting works because the posts have a
195−`yyyy-mm-dd-title.extension` naming scheme. We want the paths as `PagePath` and
196−not as `FilePath` or `String`, because `PagePath` is an instance of
197−`Renderable`. Also, we only want the 5 most recent posts.
198−
199− let renderablePosts = map createPagePath postPaths
200− let recentItems = renderAndConcat "templates/postitem.html" $ take 5 renderablePosts
201−
202−The `renderAndConcat` function takes a template and a list of `Renderable`
203−items. It renders all renderables with the given template, and concatenates the
204−result. Note that the concating and reading of pages is not executed yet,
205−because of laziness. This helps us, since we want to use the modification
206−timestamps of files, and not render everything every time.
207−
208− let rssPage = createCustomPage "rss.xml"
209− ("templates/rssitem.xml" : postPaths) [("items", Right recentItems)]
210−
211−We now created the custom rss page. The `createCustomPage` is a function that
212−produces a `CustomPage`, which is an instance of `Renderable`. `"rss.xml"` is
213−our destination url. We then give a list of extra dependencies that were used
214−to generate the custom page, so Hakyll can check modification stamps. The last
215−argument is the key-value mapping of our `CustomPage`. Note that the type for
216−values is `Either String (IO ByteString)`. So, we can either give a simple
217−string, or an IO action that results in a `ByteString`. The benefit of this is
218−that the IO action will not be executed if the page in `_site/` is already
219−up-to-date. Now, we only need to render it using our rss template.
220−
221− renderChain ["templates/rss.xml"] rssPage
222−
223−That's it. Now we have a rss feed that is generated only when it is not already
224−up-to-date.
16+More information can be found on
17+[the hakyll homepage](http://jaspervdj.be/hakyll).
hakyll.cabal+12−4
@@ -1,5 +1,5 @@
11Name: hakyll
2−Version: 0.2
2+Version: 0.3
33
44Synopsis: A simple static site generator library.
55Description:
@@ -7,7 +7,7 @@ Description:
77 creating blogs.
88Author: Jasper Van der Jeugt
99Maintainer: jaspervdj@gmail.com
10−Homepage: http://github.com/jaspervdj/Hakyll
10+Homepage: http://jaspervdj.be/hakyll
1111License: BSD3
1212License-File: LICENSE
1313Category: Text
@@ -18,8 +18,16 @@ build-type: Simple
1818library
1919 ghc-options: -Wall
2020 hs-source-dirs: src/
21− build-depends: base >= 4 && < 5, template, filepath, directory, containers, bytestring,
22− pandoc >= 1, regex-compat, network, mtl
21+ build-depends: base >= 4 && < 5,
22+ template >= 0.1,
23+ filepath >= 1.1,
24+ directory >= 1,
25+ containers >= 0.1,
26+ bytestring >= 0.9,
27+ pandoc >= 1,
28+ regex-compat >= 0.92,
29+ network >= 2,
30+ mtl >= 1.1
2331 exposed-modules: Text.Hakyll
2432 Text.Hakyll.Render
2533 Text.Hakyll.Renderable