Difference between revisions of "Template Engine"

From PCGen Wiki
Jump to: navigation, search
(Show initial implementation results)
(Add some more detail on where things are up to, add section 1c)
Line 5: Line 5:
 
We would do this in three phases:
 
We would do this in three phases:
 
# Add support for Freemarker templates for output
 
# Add support for Freemarker templates for output
# Once sufficient sheets have been converted/rewritten, deprecate support for olod sheet types
+
# Once sufficient sheets have been converted/rewritten, deprecate support for old sheet types
 
# Finally after a few releases, remove support for the old sheet types.
 
# Finally after a few releases, remove support for the old sheet types.
  
Line 12: Line 12:
 
* Simpler more consistent logic commands and more widely understood syntax
 
* Simpler more consistent logic commands and more widely understood syntax
 
* Remove one of the more complex and difficult to maintain sections of the PCGen code base.
 
* Remove one of the more complex and difficult to maintain sections of the PCGen code base.
 +
 +
== Status ==
 +
 +
Currently working on phase 1.
 +
 +
A first run at implementing FreeMarker support in PCGen has been made and can be viewed/tested at [https://github.com/jdempsey-au/pcgen/commits/freemarker_output freemarker_output Git branch]
 +
 +
This code will be merged into the PCGen trunk after the 6.2.0 release is out. FreeMarker output will be a feature of the 6.4 release.
 +
 +
Note 1b and 1c remain to be done.
  
 
== Phase 1 ==
 
== Phase 1 ==
Line 17: Line 27:
 
The aim would be to utilise the already built output system and add the ability to  
 
The aim would be to utilise the already built output system and add the ability to  
 
# Detect Freemarker templates and use the Freemarker engine to process them
 
# Detect Freemarker templates and use the Freemarker engine to process them
# Add custom directives that can be called from a template (output sheet) to allow the
+
# Add custom directives that can be called from a template (output sheet) to allow the existing output tags to be used.
existing output tags to be used.
 
  
 
This would give us a simple change-over and use our existing well tested output code base.
 
This would give us a simple change-over and use our existing well tested output code base.
Line 38: Line 47:
  
 
See [http://freemarker.org/docs/dgui_misc_userdefdir.html User Defined Directives] and [http://freemarker.org/docs/pgui_config_sharedvariables.html Shared Variables] for information on creating custom directives/tags.
 
See [http://freemarker.org/docs/dgui_misc_userdefdir.html User Defined Directives] and [http://freemarker.org/docs/pgui_config_sharedvariables.html Shared Variables] for information on creating custom directives/tags.
 
See [https://github.com/jdempsey-au/pcgen/commits/freemarker_output freemarker_output Git branch] for the first cut code.
 
  
 
For example, the sheet
 
For example, the sheet
Line 63: Line 70:
 
<p> Rogue: 11 </p></nowiki>
 
<p> Rogue: 11 </p></nowiki>
  
=== Looping ===
+
=== 1b Assisted Looping ===
  
 
Freemarker's inbuilt looping mechanism is object oriented. It expects to receive a list and process through it. In contrast, PCGen currently only outputs strings and numbers. The technique described at [http://stackoverflow.com/questions/15461721/freemarker-template-for-loop-statement For loop] can be used, but a macro should be created to make this easier and more concise. The macro will also need to deal with the empty loop scenario.
 
Freemarker's inbuilt looping mechanism is object oriented. It expects to receive a list and process through it. In contrast, PCGen currently only outputs strings and numbers. The technique described at [http://stackoverflow.com/questions/15461721/freemarker-template-for-loop-statement For loop] can be used, but a macro should be created to make this easier and more concise. The macro will also need to deal with the empty loop scenario.
 +
 +
=== 1c Object Output ===
 +
 +
To more closely align with FreeMarker's object oriented approach, we should examine the potential for exporting objects for output. So for example, exporting a list of spell objects that can then be looped over and each object queried as needed. A base for this output interface could be the Facade work done for the user interface.
 +
 +
<nowiki>
 +
<#list pc.knownspells as spell>
 +
    <li>${spell.name} School: ${spell.school} <#if spell.subschool??> [${spell.school}] </#if></li>
 +
</#list></nowiki>

Revision as of 20:46, 26 November 2013

Template Engine Sub Project

The aim of the project is to examine the Freemarker library with a view to using it to replace our export engine. In particular it would cover functionality logic functions like looping and if tests. This would leave our code to deal with the important things like TO HIT values etc.

We would do this in three phases:

  1. Add support for Freemarker templates for output
  2. Once sufficient sheets have been converted/rewritten, deprecate support for old sheet types
  3. Finally after a few releases, remove support for the old sheet types.

There are a few reasons for exploring this change

  • Add a richer set of logic commands to enable more customisable output
  • Simpler more consistent logic commands and more widely understood syntax
  • Remove one of the more complex and difficult to maintain sections of the PCGen code base.

Status

Currently working on phase 1.

A first run at implementing FreeMarker support in PCGen has been made and can be viewed/tested at freemarker_output Git branch

This code will be merged into the PCGen trunk after the 6.2.0 release is out. FreeMarker output will be a feature of the 6.4 release.

Note 1b and 1c remain to be done.

Phase 1

The aim would be to utilise the already built output system and add the ability to

  1. Detect Freemarker templates and use the Freemarker engine to process them
  2. Add custom directives that can be called from a template (output sheet) to allow the existing output tags to be used.

This would give us a simple change-over and use our existing well tested output code base.


Example of outputting an export tag

<@pcstring tag="NAME"/>
<@pcstring tag="SPELLMEM.0.1.1.1.NAME"/>
<@pcstring tag="PLAYERNAME"/>

Example of accessing a character variable value:

${pcvar("CL=Fighter")}
${pcvar("CL=Rogue")}
${pcvar("count(\"ABILITIES\",\"CATEGORY=FEAT\",\"TYPE=Metamagic\",\"VISIBILITY=DEFAULT[or]VISIBILITY=OUTPUT_ONLY\")")}

We would need to ensure that freemarker templates can be used in html, and PDF output styles.

See User Defined Directives and Shared Variables for information on creating custom directives/tags.

For example, the sheet

<!-- Produced on ${.now?date} at ${.now?time} using template ${.template_name} -->
<h1>Freemarker Sheet for <@pcstring tag="NAME"/> - ${.now?date}</h1>

<p> Character Name: <@pcstring tag="NAME"/> </p>
<p> Player Name: <@pcstring tag="PLAYERNAME"/> </p>

<p> Fighter: ${pcvar("CL=Fighter")} </p>
<p> Rogue: ${pcvar("CL=Rogue")} </p>

produced the output

<!-- Produced on 29/10/2013 at 9:44:47 PM using template csheet_test-html.ftl -->
<h1>Freemarker Sheet for Ronald 'Surefingers' Millbridge - 29/10/2013</h1>

<p> Character Name: Ronald 'Surefingers' Millbridge </p>
<p> Player Name: James </p>

<p> Fighter: 0 </p>
<p> Rogue: 11 </p>

1b Assisted Looping

Freemarker's inbuilt looping mechanism is object oriented. It expects to receive a list and process through it. In contrast, PCGen currently only outputs strings and numbers. The technique described at For loop can be used, but a macro should be created to make this easier and more concise. The macro will also need to deal with the empty loop scenario.

1c Object Output

To more closely align with FreeMarker's object oriented approach, we should examine the potential for exporting objects for output. So for example, exporting a list of spell objects that can then be looped over and each object queried as needed. A base for this output interface could be the Facade work done for the user interface.

<#list pc.knownspells as spell>
    <li>${spell.name} School: ${spell.school} <#if spell.subschool??> [${spell.school}] </#if></li>
</#list>