Savory's Blocks Library
The Blocks Library makes Prudence's HTML generation system more flexible by introducing the concept of "blocks" to the concept of fragments. Whereas fragments are complete documents, any part of a document can be marked as a "block" which can then be included in any other.
Blocks can be simple text, or "closures" (JavaScript functions) that generate output, which is automatically captured by the library.
Why would you need this? After all, you can simply define functions on your own and call them from anywhere in your document, without Savory's help. The thing is that it's not trivial to make sure you're only calling them once, or to easily handle concatenate multiple function results. Savory takes care of all that. Blocks are guaranteed to be executed no more than once per conversation. If they're not used, they're never executed, and there are no resources wasted.
The secret (shh!) is that block values are simply cached in conversation.locals. That means you can easily interact with other Prudence code, which does not use the Blocks Library.
Here's how you would define a block:
<%{{ 'greetings.hello' -> name %>
<span style="color: blue;">
Hello there, <%= name %>!
</span>
<%}}%>
And here's how you would include it:
<%&& 'greetings.hello', 'Tal' %>
Note the cool use of custom scriptlets to define and use blocks.
Live example of the above: Hello, Tal! Neat.
Note that blocks such as the above, that accept arguments, are not called once-and-only-once, but are executed anew each time with the provided arguments. Only blocks without arguments are rendered once-and-only-once.
Some use cases for blocks are detailed below.
Refer to the Savory.Blocks API documentation for more details.
Block Libraries
Your document may need to include many re-usable bits and pieces at various places, but creating a /web/fragments/ file for each one would introduce a lot of clutter, especially when it's very likely that these fragments would always be used together. Instead, you could put all the pieces in one single fragment and define them as blocks, which you can then insert separately. The fragment in this case can be considered as a "block library." You may have many of these block libraries in your application.
Because the blocks aren't rendered if they aren't used, there's no harm in including a large block library, even if you only need one block from it.
Note that it makes no sense to cache block library fragments, using Prudence's document.cacheDuration API, because you want the block to be available for execution. Instead, you'll want to cache the rendered document into which you include the blocks.
For clarity, we like naming block library fragments with "-library" in the name. For example, the greetings library used here is "greetings-library.html". Feel free to ignore this advice.
Templates
Blocks let you organize your documents according to your logic and priorities, rather than forcing you into HTML's strict top-to-bottom paradigm. You do this by first defining blocks, which correspond to parts of the HTML document, and then assemble them together in a "template." A template is any /web/fragments/ file that uses Blocks.include to assemble the parts. Templates, then, are like the reverse of block libraries.
For example, consider that in HTML literal CSS stylesheets should go in the <head>, while literal scripts should usually go after the <body>. That's annoying if what you want to do keep the relevant CSS and script together with the HTML.
Here's how a template solution could look. This is the complete /web/fragments/page-template.html file:
<%
document.executeOnce('/savory/foundation/prudence/blocks/')
%>
<html>
<head>
<title><%&& 'page.title' %></title>
<%&& 'page.head' %>
</head>
<body>
<%&& 'page.main' %>
</body>
<%&& 'page.foot' %>
</html>
We could then use it like so:
<%
document.executeOnce('/savory/foundation/prudence/blocks/')
Blocks.set('page.title', 'Welcome to Our Site!')
%>
<%# Here we'll define our head block %>
<%{{ 'page.head' %>
<style>
div {
margin: 10px;
}
</style>
<%}}%>
<%# Here we'll define our foot block %>
<%{{ 'page.foot' %>
<script>
// Reload this important page every 5 seconds
setTimeout(function() {
location.reload(true);
}, 5000);
</script>
<%}}%>
<%# Here we'll define our main block %>
<%{{ 'page.main' %>
<p>Hello!</p>
<%}}%>
<%# So far, we haven't actually executed any of the above blocks.
It's only now, when we include the template, that all blocks will be rendered. %>
<%& '/page-template/ %>
Note the use of Block.append instead of Block.set: the value (or closure's value) is added to the block, instead of replacing it. This allows you to put various style sheets or scripts into the template via multiple calls to Block.append.
Like block libraries, note that it makes no sense to cache template fragments, using Prudence's document.cacheDuration API, because you want the block to be available for execution. Instead, you'll want to cache the rendered document which includes the template.
For clarity, we like naming template fragments with "-template" in the name. For example, the template used for this site is "site-template.html". Feel free to ignore this advice.
Template Inheritence
A useful feature in many web templating engines is template inheritence. It lets you more easily design different sections of your site while maintaining a consistent design. Instead of building all your templates from scratch, you could inherit from an already existing template. Thus changes to the parent template would affect all inherited templates, allowing you to centrally manage all your templates, and thus your site.
This is easy to do with Prudence: simply introduce your overrides before including the parent template:

