= Render Actions
// tag::render-operations[]
Presently, all render actions convert AsciiDoc-formatted source files into rich-text documents, such as PDFs and HTML pages.
LiquiDoc uses Asciidoctor's Ruby engine and various other plugins to generate output in a few supported formats.

First let's look at a render action configuration step.

[source,yaml]
.Example config -- Instructing Asciidoctor conversions with 'render' action
----
- action: render
  source: book-index.adoc
  data: _configs/asciidoctor.yml
  builds:
    - output: _build/publish/codewriting-book-draft.pdf
      theme: theme/pdf-theme.yml
    - output: _build/publish/codewriting-book-draft.html
      theme: theme/site.css
----

Each action for rendering a conventionally structured book-style document requires an index, which is the primary AsciiDoc file to process labeled `source:` in our configuration.
This file can contain all of your AsciiDoc content, if you wish.
Alternatively, it can be made up entirely of `include::` macros, creating an linear map of your document's contents, which may themselves be more AsciiDoc files, code examples, and so forth.

[[_fig_index_file]]
[source,asciidoc]
.Example AsciiDoc index file
----
= This File Can Contain Regular AsciiDoc Markup

\include::chapter-01.adoc[]

\include::code-sample.rb[tags="booksample"]

\include::code-sample.js[lines="22..33"]
----

After the title line, the first macro instruction in this example will embed the entire file `chapter-01.adoc`, parsing and rendering its AsciiDoc-formatted contents in the process.

The second instruction extracts part of the file `code-sample.rb` and embeds it here.
Inside `codesample.rb`, content is tagged with comment code to mark what we wish to extract.
In the case of a Ruby file, you would expect to find code like the following in the source.

[source,ruby]
.Example Ruby code snippet tagged for inclusion
----
# tag::booksample[]
def exampleblock
  puts "This is an example for my book."
end
# end::booksample[]
----

For AsciiDoc source code, you would use the `//` comment notation.

[source,asciidoc]
.Example AsciiDoc code snippet tagged for inclusion
----
// tag::booksample[]
purpose::
to demonstrate inclusion.
// end::booksample[]
----

The third instruction in our <<_fig_index_file>>, which was simply `include::code-sample.js[lines="22..33"]` -- this dangerous little bugger extracts a fixed span of code lines, as designated.

== Static Site Render Operations

Static-site generators are critical tools to just about any docs-as-code infrastructure.
Starting with Jekyll but soon to add more (link:http://awestruct.org[Awestruct] and possibly link:https://sysgears.com/grain/[Grain] next), each generator added will maintain all of its capabilities and do most of the heavy lifting.

LiquiDoc's role is primarily to help your preferred SSG handle your source in ways consistent with any other rendering and file managing your docs codebase requires.
For example, the jekyll-asciidoc extension that enables Jekyll builds to parse AsciiDoc markup only honors attributes set in Jekyll config files.
Therefore, just before triggering the build, LiquiDoc loads all the accummulated AsciiDoc parameters into a new config file from which Jekyll draws AsciiDoc attribute assignments.

Jekyll::
A Jekyll render operation calls `bundle exec jekyll build` from the command line pretty much the way you would do it manually.
You still need a Jekyll configuration file with the usual settings in it.
This is established in your build-config block

[source,yaml]
.Example Jekyll render action
----
- action: render
  data: globals.yml
  builds:
    - backend: jekyll
      properties:
        files:
          - _configs/jekyll-global.yml
          - _configs/jekyll-portal-1.yml
        arguments:
          destination: build/site/user-basic
      attributes:
        portal_term: Guide
----

The `backend:` designation of `jekyll` is required, and at least one file under `properties:files:` is strongly encouraged for proper Jekyll behavior.
LiquiDoc will write an additional YAML file containing all of the Asciidoctor attributes, to be appended to this list when the build command is run.
This captures attributes offered up in the action-level `data:` file and in the `attributes:` section of the build step.

The `arguments:` block is made up of key-value parameters that establish or override any _Jekyll_ config settings.

[NOTE]
The action-level parameter `source:` is left blank in this example.
This setting _cannot_ be used to designate a Jekyll source path.
If the above action had a second build step, such as a single output doc, the source would have relevance as the index file for that document.

[[asciidoc-attributes]]
== Setting AsciiDoc Attributes
// tag::setting-asciidoc-attributes[]
For basic `render` actions, the `source:` file and other `.adoc` files determine most of the rest of the content source files (if any) using AsciiDoc includes.
But Asciidoctor renderings can be configured and manipulated by _attribute_ settings at other stages.
Basically, we are trying to maximize our readiness to ingest document data and build properties from a wide range of sources.
This way inline substitutions can be made out of data living outside the source tree of any particular document, passed into the document build in the form of YAML data converted into -- you guessed it -- AsciiDoc _attributes_.

[NOTE]
AsciiDoc attributes are not the same as Asciidoctor configuration properties.
While both kinds create substitutions that are expressed the same way (`{property_name}`), they are set differently in your LiquiDoc configuration.

LiquiDoc provides several means for adding attributes to your documents, in addition to the ways you might be used to setting attributes (inside your docfiles and command line).
They are listed below _in the order of assignment/substitution_.
Therefore, an identical value defined explicitly in each subsequent space will overwrite any set in the previous stages.

The order of substitution is as follows.

. <<asciidoc-doc-inline,AsciiDoc document inline>>
. <<document-data-file,document data file>>
. <<per-build-properties-files,per-build properties files>>
. <<per-build-liquidoc-config,per-build in LiquiDoc config>>
. <<command-line-arguments,command-line arguments>>

After that, we'll demonstrate even <<more-attributes-data,more ways to ingest datasets>>.

[[asciidoc-doc-inline]]
AsciiDoc document inline::
The most common way to set variables is inside your AsciiDoc source files -- typically at the top of your `index.adoc` file or the equivalent.
Any parameters set there will cascade through your included files for parsing.
This is a good place to establish defaults, but they can be overwritten by the other four means of setting AsciiDoc attributes.
+
[source,asciidoc]
.Example -- Setting AsciiDoc attributes inline
----
:some_var: My value
:imagesdir: ./img
----

[[document-data-file]]
Document data file::
A YAML-formatted data file containing a stack of key-value pairs can be passed to Asciidoctor.
+
[source,yaml]
.Example AsciiDoc attributes data file
----
imagesdir: assets/images
basedir: _build
my_custom_var: Some text, can include spaces and most punctuation
----
+
This file must be called out in your configuration using the top-level `data:` setting.
+
[source,yaml]
.Example AsciiDoc data file setting for attributes ingest
----
- action: render
  source: my_index.adoc
  data: _data/asciidoctor.yml
  builds:
    - output: myfile.html
----
+
You may also pass *multiple files* and/or just a sub-block of a given file (a named variable with its own nested data).
See <<#more-data,below>>.

[[per-build-properties-files]]
Per-build properties files::
With document-wide attributes set, we begin overwriting them on a _per-build_ basis for different renderings of that same source document.
For starters, LiquiDoc can extract attributes from still more data files at this stage, like so:
+
.Example -- Attribute extraction from build-specific data files
[source,yaml]
----
  - output: _build/publish/manual-europe.pdf
    properties:
      files: _conf/jekyll.yml,_data/europe.yml
  - output: _build/publish/manual-china.pdf
    properties:
      files: _conf/jekyll.yml,_data/china.yml
----
+
The `properties:files` setting can take the form of a comma-delimited list or a YAML array, and it can filter to specific subdata (see <<#more-data,below>>).
These per-build properties files are meant to be document settings, so for static site renderings (e.g., Jekyll), these are meant to contain YAML files formatted for Jekyll configuration reads.

[[per-build-liquidoc-config]]
Per-build in LiquiDoc config::
So if your _document_ is a book, and your _builds_ are an HTML edition and a PDF edition, you can pass distinct settings to each.
+
[source,yaml]
.Example per-build attribute settings in config file
----
  - action: render
    source: my_book.adoc
    data: _data/asciidoctor.yml
    builds:
      - output: my_book.html
        attributes:
          edition: HTML
      - output: my_book.pdf
        attributes:
          edition: PDF
      - output: my_book_special.pdf
        attributes:
          edition: Special
----
+
Imagine this affecting content in the book file.
+
[source,asciidoc]
.Example book index with variable content
----
= My Awesome Book: {edition} Edition

\include::chapter-1.adoc[]

\include::chapter-2.adoc[]
\ifeval::["{edition}" == "Special"]
\include::chapter-3.adoc[]
\endif::[]
----
+
The AsciiDoc code above that might be least familiar to you is conditional code, represented by the `ifeval::[]` and `endif::[]` markup.
Here we see how passing attributes at the _build iteration_ level gives us all kinds of cool powers.
Not only are we setting the subtitle with a variable; if we're building the special edition, we add a chapter the other two editions ignore.

[[command-line-arguments]]
Command-line arguments::
There is yet a way to override all of this, which is also handy for testing variables out without editing any files: pass arguments via the `-a` option on the command line.
The `-a` option flag accepts an argument in the format of `key=value`, where `key` is the name of your attribute, and `value` is your optional assignment for that attribute.
You may pass as many attributes as you like this way, up to the capacity of your shell's command line, which is probably something.
+
[source,bash]
.Example -- Setting global build attributes on the CLI
----
bundle exec liquidoc -c _configs/my_book.yml -a edition='Very Special NSFW'
----

[[more-attributes-data]]
== More ways to Ingest Attributes Data

multiple attribute files::
You may also specify more than one attribute file by separating filenames with commas.
They will be ingested in order.

specific subdata::
You may specify a particular block in your data file by designating it with a colon.
+
.Example -- Listing multiple data files & designating a nested block
[source,yaml]
----
  data:
    - asciidoc.yml
    - product.yml:settings.attributes
----
+
.Example -- Designating a data block -- alternate format
[source,yaml]
----
  properties:
    files: asciidoc.yml,product.yml:settings.attributes
----
+
Here we see `,` used as a delimiter between files and `:` as an indicator that a block designator follows.
In this case, the render action will load the `settings.attributes` block from the `product.yml` file.
+
.Example -- Designating data blocks within a properties files
[source,yaml]
----
  properties:
    files:
      - countries.yml:cn
      - edition.yml:enterprise.premium
----
+
In this last case, we're passing locale settings for a premium edition targeted to a Chinese audience.

// end::setting-asciidoc-attributes[]

== Render Build Settings Overview

Certain AsciiDoc/Asciidoctor settings are determinant enough that they can be set using parameters in the build config.
Establishing these as per-build settings in your config file will override anywhere else they are set, except on the command line.

[IMPORTANT]
These settings do not necessarily have 1:1 correspondence to AsciiDoc(tor) attributes.

output::
The filename for saving rendered content.
This build setting is required for render operations that generate a single file.
Static site generation renders, however, target a directory set in the SSG's config.

backend::
The backend determines the rendering context.
When building single-file output, the backend is typically determined from the `output:` filename and/or the `doctype:`.
Some renderers, such as Jekyll, require specific backend designations (`jekyll`).
Valid options are `html5`, `pdf`, `jekyll`, with more to come.

doctype::
Overrides Asciidoctor *doctype* attribute.
Valid values are:

`book`:::
Generates a book-formatted document in PDF, HTML, or ePub.

`article`:::
Generates an article-formatted document in PDF, HTML, or ePub.

`manpage`:::
Generates Linux man page format.

`deck`:::
Generates an HTML/JavaScript slide deck. (Not yet implemented.)

`style`::
Points either to a YAML configuration for PDF styles or a CSS stylesheet for HTML rendering.

variables::
Designate one or more nested variables alongside ingested data in parse actions.

properties::
Designates a file or files for settings and additional explicit configuration at the build level for render actions.
// end::render-operations[]

== Algolia Search Indexing for Jekyll

If you're using Jekyll to build sites, LiquiDoc makes indexing your files with the Algolia cloud search service a matter of configuration, not development.
The heavy lifting is performed by the link:https://community.algolia.com/jekyll-algolia/[jekyll-algolia plugin], but LiquiDoc can handle indexing even a complex site by using the same configuration that built your HTML content (which is what Algolia actually indexes).

[NOTE]
You will need a free community (or premium) link:https://www.algolia.com/users/sign_up/hacker[Algolia account] to take advantage of Algolia's indexing service and REST API.
Simply create a named index, then visit the API Keys to collect the rest of the info you'll need to get going.

Two hard-coding steps are required to prep your source to handle Algolia index pushes.

. Add a block to your main Jekyll configuration file.
+
.Example Jekyll Algolia configuration
[source,yaml]
----
algolia:
  application_id: 'your-application-id' # <1>
  search_only_api_key: 'your-search-only-api-key' # <2>
  extensions_to_index: [adoc] # <3>
----
+
<1> From the top bar of your Algolia interface.
<2> From the API Keys screen of your Algolia interface.
<3> List as many extensions as apply, separated by commas.

. Add a block to your build config.
+
[source,yaml]
----
  - action: render
    data: globals.yml
    builds:
      - backend: jekyll
        properties:
          files:
            - _configs/jekyll-global.yml
            - _configs/jekyll-portal-1.yml
          arguments:
            destination: build/site/user-basic
        attributes:
          portal_term: Guide
        search:
          index: 'portal-1'
----
+
The `index:` parameter is for the name of the index you are pushing to.
(An Algolia “app” can have multiple “indices”.)
This entry _configures_ but does not _trigger_ an indexing operation.

Indexing is invoked by command-line flags.
Add `--search-index-push` or `--search-index-dry` along with the `--search-api-key='your-admin-api-key-here'` argument in order to invoke the indexing operation.
The `--search-index-dry` flag merely tests content packaging, whereas `--search-index-push` connects to the Algolia REST API and attempt to push your content for indexing and storage.

.Example Jekyll Algolia deployment
[source,shell]
----
bundle exec liquidoc -c _configs/build-docs.yml --search-index-push --search-index-api-key='90f556qaa456abh6j3w7e8c10t48c2i57'
----

This operation performs a complete build, including each render operation, before the Algolia plugin processes content and pushes each build to the indexing service, in turn.

[TIP]
To add modern site search for your users, add
link:https://community.algolia.com/instantsearch.js/[Algolia's InstantSearch
functionality] to your front end!
