There are lots of different ways of defining metadata as atomic values, complex objects, or powerful lazily evaluated scripts and delegates.

Generally, metadata can be any instance of any type. Statiq's powerful type conversion will help convert the metadata object to whatever type you need when you retrieve the value. Sometimes though, you need to define metadata that's a little more powerful. The sections below describe types of metadata values that are treated separately.

Computed Values

There are many cases where being able to define metadata as a computed value can be valuable. You can define computed metadata with "fat arrow" syntax. For example, placing this in the front matter of a document will result in an int of "3" being returned for the "MyNumber" metadata key:

MyNumber: => 1 + 2
My number is <?#= MyNumber /?>.

The actual value should be a string (the YAML syntax above assumes a string value) that starts with => and is a full C# script. It can even include multiple statements:

MyNumber: "=> { int x = 1 + 2; int y = x; return y; }"

The script also has access to a number of predefined global properties available to it (see the ScriptBase class in Statiq.Core for all script properties):

  • ExecutionState contains the current IExecutionState object.
  • Context (and the ctx shorthand) contain the current execution context.
  • Document (and the doc shorthand) contain the current document.
  • PipelineName: Gets the name of the currently executing pipeline.
  • Pipeline: Gets the currently executing pipeline.
  • Phase: Gets the currently executing phase of the current pipeline.
  • Parent: Gets the parent execution context if currently in a nested module.
  • Module: Gets the current executing module.
  • Inputs: The collection of input documents to the current module.

In addition, all metadata conversion methods are exposed as global methods. For example, if a document has another metadata value called Foo and you wanted to get the int value of that in another metadata value you could write something like this in your front matter:

Bar: => GetInt("Foo") + 2

Configuration Delegates

Another way of accessing the current document or execution context while computing a lazy metadata value is to use a configuration delegate. When an instance of IConfig is added as a metadata value, it will be evaluated on every request for that value.

Lazy Values

In more advanced scenarios you sometimes want to defer figuring out the value of a metadata item until it’s accessed. This can help when the data to determine the value isn’t available yet, when computing the value would be expensive and you don’t know if it’ll actually need to be accessed, or you want to compute a fresh value each time it’s accessed. This can be accomplished by implementing IMetadataValue. If an object that implements that interface is added as a metadata value, it’s object Get(IMetadata metadata) method will be called when the value is requested (the metadata argument is the current metadata object, for example the document).