CHANGES v1.9 ============ * Added the freemarker.engine package. Added extra examples that show FMEngine and FMModel being used. Altered the freemarker.doc package to use the freemarker.engine package. * Moved test cases to a separate source directory. * Hash literals can use the colon character as a separator between a key and its value, similar to JSON format. * String literals take unicode escape sequences same as JSON format. * Added element, mainly for use in conjunction with and block instructions. Can either be scope all variables in the block, or named variables. Can be used to capture scope for lambda expressions. * Functions declared inside other functions or within a local block are scoped within the containing function or local. * Made statement an optional block element, a-la JSTL. - RootModelWrapper is now a part of the core package, rather than an extension. - Empty assign and block assign are separate instruction classes. - Some minor changes to StandardTemplateParser, findTagEnd() method is refactored, as is parseAssign(). - Added test cases for this behaviour. - Need to update the manual to reflect this behaviour. * Functions take on Awk behaviour regarding local variables: any declared variable without a matching parameter in the instruction becomes an empty local variable. - Need to update the manual to reflect this behaviour. * Functions can be nested. When one function is defined inside another, the definition exists within the scope of the outer function. It can then be reassigned to a global variable. Note that defining an inner function does not by itself capture the scope of the outer function. * Added an #empty special identifier, which returns a null model. - Take special note of the behaviour of the Plus operator when it interacts with null models. Always returns a Scalar model. - Regularised the parser so that #true, #false, and #empty can be on the left hand size of a binary expression. - Need to update the manual to reflect this behaviour. * Added a #lambda expression, to assist with the functional models (see below). - This is a unary prefix operator. Fixed up the ExpressionBuilder to handle consecutive unary prefixes so that they are correctly right-associative. - This works a-la Python, except that ternary operators are now available (see below). - Need to update the manual, as a special subsection of method models and/or functional programming. * Added a conditional ternary expression, mainly useful with lambda expressions. - Ternary is the most loosely associated operator, mainly out of necessity to make the parser simpler, and to allow the ternary operator to be nestable. - Update the manual. * Added a Pipeline method model, which takes a parameter list of Transform or Transform2 objects and returns a wrapping Transform2 object that calls each one in turn. - Documented which order the transformations occur, and whether this is equivalent to nesting instructions. * Added a Join method model, which is the complement of the Split model. The Split model itself has had a minor rework. * Added the Transliterate library as methods and transforms, similar to the Substitute models. - Added test cases for this model. * Added filter, map, and reduce methods and transforms, for basic functional programming. - Maybe add a section to the manual about functional programming. - See also the #lambda expression. * Added the new models to the Methods and Transforms classes. * Improved the way the reflection library deals with numbers and number conversions from the internal template models. - Add more test cases for this model. * Abstracted FunctionModel into a TemplateFunctionModel interface with appropriate warnings and hazard lights. This allows expert users most of the power of an empty instruction without having to extend the parser. - Refactored Template and FunctionTemplateProcessor to deal with TemplateFunctionModel. This gives some added flexibility as to when and how such models can be stored and retrieved. - Changed the serialized form of Template as a result, since the internal data model has changed. A new serialization UID has been generated. - Added a simple model to the test cases and exercise it. * Added a getAsStringOrEmpty() method to TemplateUtils class, and use it in several places instead of the getAsString() method. Makes the class more user friendly, especially for TemplateMethodModel2 handling. * Created TemplateWriteableIndexedModel and TemplateWriteableHashModel interfaces, primarily used with the beans2 package. Reworked a lot of related expression code so that any variable model can potentially be the left-hand-side of an assignment. Consequential changes to AssignInstruction and StandardTemplateParser made. * Use an InputSource interface and concrete classes, similar to the SAX 2 library, to pass input streams into the Template constructor. Simplifies a lot of related constructors. Also allows us to pass in the name of the template (as per the template cache) without compromising the immutability of the template. See also Source in the TRaX library. * Also created FileInputSource and StringInputSource sublasses of InputSource. * Pushed up the concept of InputSource into the StandardTemplateParser, so that the parser isn't completely tied to reading its input from a String source. * FastList now implements TemplateWriteableIndexedModel. * Created a rewrite of the freemarker.ext.beans classes (beans2). The old package is becoming difficult to maintain, and the current license is a problem. - Need to extensively document the behaviour of the new package. * Created a separate formatters package, with classes for MessageFormat, DateFormat, and NumberFormat. * Created wrapper TemplateWriteableHashModel classes for calling globally-scoped functions and list iterations. Made list items "live" (long "i") by extending TemplateIteratorModel to add a "set(TemplateModel m)" method. A lot of intelligence ends up in the wrapping list iteration model. The "remove(String key)" method from the TemplateModelRoot interface becomes redundant as a result. * Writeable models always extend the read-only models. This eliminates the need for TemplateModelRoot altogether, which becomes a marker interface only. Retrofitted all existing uses of TemplateModelRoot back to TemplateWriteableHashModel. * Added a lambda operator, for creation of simple anonymous methods. - These capture variable scope at declaration time, to support closures. - Very similar to Python in design. - Can be used in conjunction with filter, map, and reduce methods, also like the Python functional methods. * Added the conditional ternary operator, typical to common languages such as C, Java, and so on. * Deleted deprecated classes from the freemarker.ext.misc package.