在 Hakyll 中从元数据创建列表字段

Creating a list field from metadata in Hakyll

我正在尝试为 Hakyll 中的 post 生成 HTML,它们的元数据中有 versions 条目。例如,post 可能有 versions: Python 3.4, pytest 1.5.2,它可以很好地格式化在 post.

的底部

为此,我想创建一个加载元数据并创建 ListField 的上下文。类似于以下存根:

versionsCtx :: Context String
versionsCtx = listFieldWith "versions" ctx (\item -> do
    versions <- getMetadataField (itemIdentifier item) "versions"

    return $ case versions of
      Just lst -> map (mkVersinoItem . trim) $ splitAll "," lst
      Nothing  -> [])
          where ctx = field "version" (return . itemBody)
                mkVersionItem version = Item {
                    itemIdentifier = fromString ("version/" ++ version),
                    itemBody = version
                }

在我的 post.html 模板中,我有:

...
    <section>
        $body$

        $if(versions)$
        <hr />
        <ul>
            $for(versions)$
                <li>$version$</li>
            $endfor$
        </ul>
        $else$
            <p>Fail...</p>
        $endif$
    </section>
...

然而我尝试了很多不同的 versionsCtx 定义,并在网上找到了类似的尝试。 None 似乎有效并且 post 总是用 "Fail..." 渲染。我做错了什么?

编辑:更新问题并提供建议和说明。

您的代码存在多个问题:

  1. getMetadataField 提供了一个 Maybe 类型,在 Haskell 中有数据构造函数 JustNothing,而不是 SomeNone.
  2. makeItem 函数创建一个 Item 已经包裹在 Compiler 中,导致以下错误:
• Couldn't match type ‘Compiler (Item String)’ with ‘Item String’
  Expected type: Compiler [Item String]
    Actual type: Compiler [Compiler (Item String)]

虽然您可以尝试从中提取项目,但使用类似这样的方法从头开始创建项目可能更干净:

mkVersionItem version = Item {
    itemIdentifier = fromString ("version/" ++ version),
    itemBody = version
}
  1. 我没有看到您将新创建的上下文添加到 post 上下文中。你做到了吗?
  2. docs, the order Contexts are being appended is important. It is not evident from your question, but you are probably using defaultContext, which includes metadataField所述。您的 post 的元数据块中有 versions 字段,因此当 defaultContext 获胜时,它将使 versions 可用作模板中的字符串字段。当 versions 是字符串字段时,$if(versions)$ 由于某种原因跳转到 else 分支,这解释了为什么显示“失败”。当您将 for 循环移动到条件块之外时,您可以在控制台中看到更多信息错误:
[ERROR] Hakyll.Web.Template.applyTemplateWith: expected ListField but got StringField for expr versions

完整的代码看起来像这样:

import           Data.String (fromString)

postCtx :: Context String
postCtx =
    versionsCtx `mappend`
    dateField "date" "%B %e, %Y" `mappend`
    defaultContext

versionsCtx :: Context String
versionsCtx = listFieldWith "versions" ctx (\item -> do
    versions <- getMetadataField (itemIdentifier item) "versions"

    return $ case versions of
      Just lst -> map (mkVersionItem . trim) $ splitAll "," lst
      Nothing     -> []
    )
  where
    ctx = field "version" (return . itemBody)
    mkVersionItem version = Item {
        itemIdentifier = fromString ("version/" ++ version),
        itemBody = version
    }