How do I interpolate $key$s in a file without applying a template? - hakyll

In Jekyll it is possible to have a file that looks like
---
title: Whatever
layout: null
---
<h1>{{ title }}</h1>
The {{ title }} will be interpolated, but the layout: null means that the file contents won’t be wrapped in any kind of template.
What is the equivalent in Hakyll? In other words, if I have a self-contained file like
<h1>$title$</h1>
what kind of block do I need to pass to compile in order to have the $title$ value interpolated, without wrapping the page’s contents in some template?

The answer (thanks to erasmas in the #hakyll channel!) is to compile your page using
getResourceBody >>= applyAsTemplate theContext
where theContext is the instance of Context String that contains the fields you want.
Here’s a toy example of how you’d use this compiler:
main :: IO ()
main = hakyll $ do
match "index.html" $ do
route idRoute
compile $ getResourceBody >>= applyAsTemplate indexContext
indexContext :: Context String
indexContext = mconcat
[ constField "title" "My Website"
, defaultContext
]

Related

How to use Template Literals in Cypress It() command description

When I put a template literal in the description of an It command, the template literal does not get evaluated, instead, the template literal code is displayed.
let title = "Page Tile";
it('Find Page Title = ${title}' , function () {
cy.title({ timeout: 90000 }).should('include', title)
});
The output looks like: Find Page Title = ${title}
I was hoping for output of: Find Page Title = Page Tile
Make sure you are using backticks. `` instead of ''.

Jinja2 templated file with json safe multiline include

I have a problem with a Jinja2 template I'm writing (called from Ansible).
The resultant file is a JSON file that I will send to an API (either with Ansible URI module or with curl). The template looks like this and basically works:
{
"description" : "my description",
"pipeline": "{% include 'root/pipeline.j2' %}"
}
The problem is that the content of root/pipeline.j2 is quite complex and includes multiple lines, quote characters and any number of other things that make the json file I'm creating invalid. What I want to do is parse the included file through a filter to convert it to a JSON valid string; something like this:
{
"description" : "my description",
"pipeline": "{% include 'root/pipeline.j2' | to_json %}"
}
But that doesn't work, probably because the filter is acting on the filename, not the included content.
Just for a little clarity when I create the template at the moment I see pipeline gets set to something like this:
"pipeline": "input {
"input1" {
<snipped>
"
It should appear thus:
"pipeline": "input {\n \"input1\" {<snipped>"
NB: I'm only giving the first couple of lines and I am using 'snipped' where I have remove the rest of the config.
Can anyone tell me how I can use an include within a jinja2 template that renders the result as a single line valid json string?
Thanks in advance for any assistance.
I finally managed to find a solution to my own question. Within the template that provides the JSON that is an API payload I am now setting a variable to the content of the pipeline template, which makes it easy to filter it with to_json:
{% set pipeline = lookup('template', 'root/pipeline.j2') %}
{
"description" : "my description",
"pipeline": {{ pipeline | to_json }}
}
I will leave this quesiton answer open for a while in case anyone can supply a better answer or explain why this is not a good one.
Thanks.

Inserting template name as class

When creating a Go template, you can give it a name, like in this example, "my_home_template":
var tmplHome = template.Must(template.New("my_home_template").Funcs(funcMap).ParseFiles("templates/base.tmpl", "templates/content_home.tmpl"))
How can I get that template name and use it inside the actual template file?
Ultimately I just want to define a convenient css class, like so:
<body class="my_home_template">
Here's a working solution, taking mkopriva's advice:
When executing a template, pass some custom parameter with dummy data. Here, I just create a "PageHome" parameter to pass to the template, and value is a simple "1", but it could be any value:
tmplHome.ExecuteTemplate(w, "base", map[string]interface{}{"PageHome": "1", "Data": events, "UserFirstName": &u.FirstName, "UserProfilePic": &u.ProfilePic})
Then, inside the template itself, a simple if statement to check if the parameter exists, and do something accordingly:
{{ if .PageHome }}
<body class="PageHome">
{{ else }}
<body>
{{ end }}
All my other template executions don't pass a "PageHome" parameter at all, so the if statement never passes as true for them.
There's probably a more advanced solution using a functions via a template function map, and having a consistent "PageType":"something" parameter in all template executions, but in the end you still have to define a parameter per template execution and still have to build up if statements in your templates anyways.

How to use variable in Nokogiri contains

I have an XML file like:
<main>
<key>xxx</key>
<key>yyy</b>
<key>zzz</key>
</main>
To check whether the XML has a node with text "yyy", I can use:
xml = Nokogiri::XML(file)
if xml.at('main/key:contains("yyy")')
#code will go here
end
But if the text value is a variable how can I use the same statement?
Note: I have tried below solution and it doesn't work:
var = "yyy"
if xml.at("main/key:contains(#{var})")
"main/key:contains(#{var})"
interpolates to to
"main/key:contains(yyy)"
Note the absence of quotes. You want this:
"main/key:contains(\"#{var}\")"
or more prettily
%Q{main/key:contains("#{var}")}
and some clever escaping would also help if you are not sure about the content of var.

Generate HTML documentation for a FreeMarker FTL library

I've a FreeMarker library that I want to ship with my product, and I'm looking for a way to generate a HTML documentation for it based on the comments in the FTL file (in a Javadoc fashion).
For example, a typical function in my library is written like:
<#--
MyMacro: Does stuff with param1 and param2.
- param1: The first param, mandatory.
- param2: The second param, 42 if not specified.
-->
<#macro MyMacro param1 param2=42>
...
</#macro>
I didn't find anything on that subject, probably because there is no standard way of writing comments in FreeMarker (Such as #param or #returns in Javadoc).
I don't mind rolling my own solution for that, but I'm keen on using an existing system like Doxia (since I'm using Maven to build the project) or Doxygen maybe, instead of writing something from scratch.
Ideally I'd like to write the comment parsing code only, and rely on something else to detect the macros and generate the doc structure.
I'm open to changing the format of my comments if that helps.
In case you decide to write your own doc generator or to write a FTL-specific front-end for an existing document generator, you can reuse some of FreeMarker's parsing infrastructure:
You can use Template.getRootTreeNode() in order to retrieve the template's top level AST node. Because macros and the responding comments should be direct children of the this top level node (IIRC), iterating over its children and casting them to the right AST node subclass should give you almost everything you need with respect to FTL syntax. To illustrate the approach I hacked together a little "demo" (cfg is a normal FreeMarker Configuration object):
Template t = cfg.getTemplate("foo.ftl");
TemplateElement te = t.getRootTreeNode();
Enumeration e = te.children();
while(e.hasMoreElements()) {
Object child = e.nextElement();
if(child instanceof Comment) {
Comment comment = (Comment)child;
System.out.println("COMMENT: " + comment.getText());
} else if(child instanceof Macro) {
Macro macro = (Macro)child;
System.out.println("MACRO: " + macro.getName());
for(String argumentName : macro.getArgumentNames()) {
System.out.println("- PARAM: " + argumentName);
}
}
}
produces for your given example macro:
COMMENT:
MyMacro: Does stuff with param1 and param2.
- param1: The first param, mandatory.
- param2: The second param, 42 if not specified.
MACRO: MyMacro
- PARAM: param1
- PARAM: param2
How you parse the comment is then up to you ;-)
Update: Found something called ftldoc in my backups and uploaded it to GitHub. Maybe this is what you are looking for...

Resources