EJS::Template - EJS (Embedded JavaScript) template engine
Version 0.09
EJS is an "Embedded JavaScript" template engine.
Anything inside the tag <%...%> is executed as JavaScript code, and anything inside the tag <%=...%> is replaced by the evaluated value.
<%...%>
<%=...%>
# Perl use EJS::Template; EJS::Template->process('source.ejs', {name => 'World'}); # EJS ('source.ejs') <% for (var i = 0; i < 3; i++) { %> Hello, <%= name %>! <% } %> # Output (STDOUT) Hello, World! Hello, World! Hello, World!
In the above example, the process() method takes an input file path as the first argument and variables passed to JavaScript as the second argument. The output is printed out to STDOUT by default.
process()
The process() method can optionally take both input and output targets (file paths, IO handles, or scalar refs to strings).
EJS::Template->process('source.ejs', {name => 'World'}, 'destination.ejs');
A simpler way to apply a template without an external file is to use apply() method, which looks something like this:
apply()
my $text = EJS::Template->apply('Hello, <%= name %>!', {name => 'World'});
Within <%...%>, it is also possible to call print() function:
print()
# EJS <% for (var i = 0; i < 3; i++) { print("i = ", i, "\n"); } %> # Output i = 0 i = 1 i = 2
EJS::Template supports auto-escaping that minimizes the risk of forgetting HTML-escape every individual variable. (See "Auto-escaping" for more details.)
EJS::Template
# Perl my $ejs = EJS::Template->new(escape => 'html'); # Set default escape type $ejs->process('sample.ejs', { address => '"Foo Bar" <foo.bar@example.com>', # to be escaped message => '<p>Hello, <i>World</i>!<p>', # not to be escaped }); # EJS ('<%=' escapes the value, while '<%:raw=' does *not*) <h2><%= address %></h2> <div> <%:raw= message %> </div> # Output <h2>"Foo Bar" <foo.bar@example.com></h2> <div> <p>Hello, <i>World</i>!</p> </div>
Extra white spaces around <% and %> are appropriately trimmed so that the result output will look fairly clean intuitively.
<%
%>
<ul> <% for (...) { %> <li>...</li> <% } %> </ul>
In the above example, the for-loop line has the indent whitespace and the line break at the end. In order to make the result HTML look clean, these whitespaces are automatically removed. See "Trimming white spaces" for more details.
for
EJS is a template with JavaScript code embedded, and this module provides a template engine to generate output from EJS templates.
It can be used as a general-purpose template engine to generate text documents, configurations, source code, etc. For web applications, EJS can be used as a template of HTML.
EJS is suitable when template authors should not embed potentially dangerous code such as file system manipulations, command executions, and database connections, while at the same time, they can still utilize JavaScript as a well-established programming language.
Especially for web applications, there are several different approaches to implement similar EJS functionality, such as parsing EJS and/or executing JavaScript on the server side or the browser side. This module implements both parsing and executing on the server side from that perspective.
Creates an EJS::Template object with configuration name/value pairs.
Usage:
my $ejs = EJS::Template->new( [NAME => VALUE, ...] );
Available configurations are as below:
escape => ESCAPE_TYPE
Sets the default escape type for all the interpolation tags (<%=...%>).
Possible values are: 'raw' (default), 'html', 'xml', 'uri', and 'quote'. See "Auto-escaping" for more details.
'raw'
'html'
'xml'
'uri'
'quote'
engine => ENGINE_CLASS
Sets the JavaScript engine class. See "JavaScript engines" for more details.
# Simple EJS::Template->process([INPUT [, VARIABLES [, OUTPUT ] ] ]); # Custom my $ejs = EJS::Template->new(...); $ejs->process([INPUT [, VARIABLES [, OUTPUT ] ] ]);
INPUT is the EJS source (default: STDIN). It can be either a string (as a file path), a string ref (as a source text), or an open file handle.
VARIABLES is a hash ref that maps variable names to values, which are made available in the JavaScript code (default: an empty hash). The values of VARIABLES can be a nested structure of hashes, arrays, strings, numbers, and/or subroutine refs. A function (subroutine) named print is automatically defined, unless overwritten in VARIABLES.
print
OUTPUT is where the final result is written out (default: STDOUT). It can be either a string (as a file path), a string ref (as a source text), or an open file handle.
Examples:
# Reads the file 'source.ejs' and prints the result to STDOUT EJS::Template->process('source.ejs', {name => 'World'}); # Reads STDIN as the EJS source and writes the result to the file 'output.txt' EJS::Template->process(\*STDIN, {name => 'World'}, 'output.txt'); # Parses the EJS source text and stores the result to the variable $out my $out; EJS::Template->process(\'Hello <%=name%>', {name => 'World'}, \$out);
EJS::Template->apply(INPUT_TEXT [, VARIABLES])
Example:
my $text = EJS::Template->apply('Hello <%= name %>', {name => 'World'}); print $text;
This method serves as a syntax sugar for the process() method, focused on text-to-text conversion.
EJS::Template->parse([INPUT [, OUTPUT ] ]);
INPUT is the EJS source, and OUTPUT is a JavaScript code, which can then be executed to generate the final output. (See execute() method.)
execute()
The parsed code can be stored in a file as an intermediate code, and can be executed at a later time.
The semantics of INPUT and OUTPUT types are similar to process().
EJS::Template->execute([INPUT [, VARIABLES [, OUTPUT ] ] ]);
INPUT is a JavaScript code generated by parse() method, and OUTPUT is the final result.
parse()
EJS::Template->context;
Retrieves the EJS::Template object under the current execution context.
It is useful when retrieving the object from within the JavaScript execution.
my $template = EJS::Template->new(); $template->process(\*STDIN, { callFromJS => sub { my $context = EJS::Template->context; # In this case, $context is the same as $template. ... } });
The above example is trivial because the current context can also be easily referenced from the outer $template variable via the closure. However, even if this subroutine is defined in some other places, the current template object can always be retrieved via this call.
$template
Gets or sets an EJS::Template::Parser object.
EJS::Template::Parser
# Getter $template->parser; # Setter $template->parser(EJS::Template::Parser->new($template));
Gets or sets an EJS::Template::Executor object.
EJS::Template::Executor
# Getter $template->executor; # Setter $template->executor(EJS::Template::Executor->new($template));
Binds name-value pairs to the associated JavaScript engine.
$template->bind({name1 => $value1}); $template->apply('<% print("name1 = ", name1) %>');
Invokes the eval() function of the associated JavaScript engine.
eval()
$template->eval('new Date().toString()');
Prints text to the current output target.
$template->print('Hello, World!');
This method can only be called under the execution context, usually from within a subroutine invoked by JavaScript.
$template->process('example.ejs', { callFromJS => sub { $template->print('Hello, World!'); } });
EJS::Template supports auto-escaping if it is configured via the new() method.
new()
EJS::Template->new(escape => 'html')->process(...);
If the escape is set to 'html', all the texts inside <%=...%> are HTML-escaped automatically.
escape
# Input <% var text = "x < y < z"; %> <span><%= text %></span> # Output <span>x < y < z</span>
In case a raw HTML needs to be embedded without escaping, it can be annotated like this:
<%:raw= text %>
In addition, the following escape types are available in a similar manner (both for the escape => config or in each individual tag <%=...%>):
escape =>
html
<span><%:html= plainText %></span>
xml
<xml><%:xml= plainText %></xml>
uri
<a href="http://example.com?name=<%:uri= value %>">Link</a>
quote
<script type="text/javascript"> var text = "<%:quote= value %>"; </script>
raw
<div><%:raw= htmlText %></div>
EJS::Template trims appropriate white spaces around <%...%> (but not around <%=...%>).
It helps the template author generate a fairly well-formatted output:
EJS:
<ul> <% for (var i = 1; i <= 5; i++) { %> <li> <% if (i % 2 == 1) { %> <%=i%> x <%=i%> = <%=i * i%> <% } %> </li> <% } %> </ul>
Output:
<ul> <li> 1 x 1 = 1 </li> <li> 3 x 3 = 9 </li> <li> 5 x 5 = 25 </li> </ul>
Note: If no white spaces were trimmed, the result output would look much more ugly, because of extra indent spaces and line breaks around <% for (...) %>, <% if (...) %>, etc.
<% for (...) %>
<% if (...) %>
The trimming occurs only when <% is at the beginning of a line with any indent spaces, and its corresponding %> is at the end of the same or another line with any trailing spaces.
When the above trimming condition is met, any white spaces to the left of <% (not including any line breaks) and any white spaces to the right of %> (including the line break) are trimmed.
In the current version, the data conversion is limited to basic types (strings, numbers, hashes, arrays, and functions), although arbitrarily nested structures are allowed.
EJS::Template->process('sample.ejs', { name => 'World', hash => {foo => 123, bar => 456, baz => [7, 8, 9]}, array => ['a'..'z'], square => sub { my $value = shift; return $value * $value; } });
If a blessed reference in Perl is passed to EJS, it is converted into a basic type.
If a Perl subroutine is invoked from inside EJS, the types of the arguments depend on the JavaScript engine that is in use internally (See "JavaScript engines").
# Perl sub printRefs { print(ref($_) || '(scalar)', "\n") foreach @_; } EJS::Template->process(\<<END, {printRefs => \&printRefs}); <% printRefs( 'str', 123, [4, 5, 6], {x: 7, y: 8}, function () {return 90} ); %> END # Output with JavaScript::V8 (scalar) (scalar) ARRAY HASH CODE # Output with JE JE::String JE::Number JE::Object::Array JE::Object JE::Object::Function
For portability, it is recommended to keep data types as simple as possible when data is passed between Perl and EJS.
EJS::Template automatically determines the available JavaScript engine from the below:
V8 (same engine as Google Chrome):
JavaScript::V8 (default for EJS::Template)
SpiderMonkey (same engine as Mozilla Firefox):
JavaScript
JavaScript::SpiderMonkey
Pure Perl implementation
JE
It is also possible to specify a particular engine:
EJS::Template->new(engine => 'JE')->process(...); EJS::Template->new(engine => 'JavaScript::SpiderMonkey')->process(...);
Caveat: JavaScript::SpiderMonkey (as of version 0.25) seems to have an issue when it is instantiated multiple times due to the shared $GLOBAL object. As a result, ESJ::Template should not be instantiated multiple times with JavaScript::SpiderMonkey used as the engine. Since it could be used implicitly when it is the only installed JavaScript module, you may need to explicitly specify another engine such as JE to avoid the issue.
$GLOBAL
ESJ::Template
Although this module does not provide the include function as a built-in, it can be implemented as below, depending on the use case.
include
# Perl my $template = EJS::Template->new({escape => 'html'}); $template->process('index.html.ejs', { include => sub { my ($path) = @_; # TODO: Validate $path to avoid reading arbitrary files my $context = EJS::Template->context; $context->process($path); } }); # EJS (index.html.ejs) <% include('header.html.ejs'); include('content.html.ejs'); include('footer.html.ejs'); %>
Some JavaScript engines correctly translate Unicode strings in Perl (utf8 flag turned on) into Unicode strings in JavaScript, and vice versa.
# Perl to JavaScript use utf8; my $input = "{Unicode string}"; EJS::Template->process(\'<%=str%>', {str => $input}); # JavaScript to Perl my $output; EJS::Template->process(\'<%func("{Unicode string}")%>', { func => sub {$output = shift} });
Currently, JavaScript::V8 and JE work as expected, but SpiderMonkey-based engines seem to have issues with Unicode as below.
JavaScript::V8
If Unicode strings in Perl are passed to JavaScript, then the strings are unexpectedly encoded as UTF-8, where each character in JavaScript strings corresponds to each byte of UTF-8 characters.
If Unicode strings in JavaScript are passed to Perl, then the strings may become corrupted.
Mahiro Ando, <mahiro at cpan.org>
<mahiro at cpan.org>
Please report any bugs or feature requests to bug-ejs-template at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=EJS-Template. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.
bug-ejs-template at rt.cpan.org
You can find documentation for this module with the perldoc command.
perldoc EJS::Template
You can also look for information at:
GitHub repository (report bugs here)
https://github.com/mahiro/perl-EJS-Template
RT: CPAN's request tracker (report bugs here, alternatively)
http://rt.cpan.org/NoAuth/Bugs.html?Dist=EJS-Template
AnnoCPAN: Annotated CPAN documentation
http://annocpan.org/dist/EJS-Template
CPAN Ratings
http://cpanratings.perl.org/d/EJS-Template
Search CPAN
http://search.cpan.org/dist/EJS-Template/
Many thanks to authors of JavaScript engines for making them available, and to authors of those in the SEE ALSO section for giving me ideas and inspirations.
Template Toolkit (a.k.a. TT)
Template::Toolkit
JavaScript Template engine based on TT2
Jemplate
Browser-side EJS
http://embeddedjs.com/
https://github.com/visionmedia/ejs
EJS for Ruby:
https://github.com/sstephenson/ruby-ejs
Copyright 2012 Mahiro Ando.
This program is free software; you can redistribute it and/or modify it under the terms of either: the GNU General Public License as published by the Free Software Foundation; or the Artistic License.
See http://dev.perl.org/licenses/ for more information.
To install EJS::Template, copy and paste the appropriate command in to your terminal.
cpanm
cpanm EJS::Template
CPAN shell
perl -MCPAN -e shell install EJS::Template
For more information on module installation, please visit the detailed CPAN module installation guide.