blib/lib/EJS/Template.pm | |||
---|---|---|---|
Criterion | Covered | Total | % |
statement | 65 | 71 | 91.5 |
branch | 17 | 30 | 56.6 |
condition | 6 | 12 | 50.0 |
subroutine | 16 | 16 | 100.0 |
pod | 11 | 11 | 100.0 |
total | 115 | 140 | 82.1 |
line | stmt | bran | cond | sub | pod | time | code |
---|---|---|---|---|---|---|---|
1 | 8 | 8 | 27487 | use 5.006; | |||
8 | 16 | ||||||
2 | 8 | 8 | 27 | use strict; | |||
8 | 10 | ||||||
8 | 151 | ||||||
3 | 8 | 8 | 25 | use warnings; | |||
8 | 16 | ||||||
8 | 235 | ||||||
4 | |||||||
5 | =head1 NAME | ||||||
6 | |||||||
7 | EJS::Template - EJS (Embedded JavaScript) template engine | ||||||
8 | |||||||
9 | =cut | ||||||
10 | |||||||
11 | package EJS::Template; | ||||||
12 | |||||||
13 | 8 | 8 | 2535 | use EJS::Template::Executor; | |||
8 | 13 | ||||||
8 | 209 | ||||||
14 | 8 | 8 | 2608 | use EJS::Template::Parser; | |||
8 | 11 | ||||||
8 | 4654 | ||||||
15 | |||||||
16 | =head1 VERSION | ||||||
17 | |||||||
18 | Version 0.08 | ||||||
19 | |||||||
20 | =cut | ||||||
21 | |||||||
22 | our $VERSION = '0.08'; | ||||||
23 | |||||||
24 | our @CONFIG_KEYS = qw(engine escape); | ||||||
25 | our $context; | ||||||
26 | |||||||
27 | =head1 SYNOPSIS | ||||||
28 | |||||||
29 | EJS is an "Embedded JavaScript" template engine. | ||||||
30 | |||||||
31 | Anything inside the tag C<< <%...%> >> is executed as JavaScript code, | ||||||
32 | and anything inside the tag C<< <%=...%> >> is replaced by the evaluated value. | ||||||
33 | |||||||
34 | # Perl | ||||||
35 | use EJS::Template; | ||||||
36 | EJS::Template->process('source.ejs', {name => 'World'}); | ||||||
37 | |||||||
38 | # EJS ('source.ejs') | ||||||
39 | <% for (var i = 0; i < 3; i++) { %> | ||||||
40 | Hello, <%= name %>! | ||||||
41 | <% } %> | ||||||
42 | |||||||
43 | # Output (STDOUT) | ||||||
44 | Hello, World! | ||||||
45 | Hello, World! | ||||||
46 | Hello, World! | ||||||
47 | |||||||
48 | In the above example, the C |
||||||
49 | first argument and variables passed to JavaScript as the second argument. | ||||||
50 | The output is printed out to STDOUT by default. | ||||||
51 | |||||||
52 | The C |
||||||
53 | paths, IO handles, or scalar refs to strings). | ||||||
54 | |||||||
55 | EJS::Template->process('source.ejs', {name => 'World'}, 'destination.ejs'); | ||||||
56 | |||||||
57 | A simpler way to apply a template without an external file is to use C |
||||||
58 | method, which looks something like this: | ||||||
59 | |||||||
60 | my $text = EJS::Template->apply('Hello, <%= name %>!', {name => 'World'}); | ||||||
61 | |||||||
62 | Within C<< <%...%> >>, it is also possible to call C |
||||||
63 | |||||||
64 | # EJS | ||||||
65 | <% | ||||||
66 | for (var i = 0; i < 3; i++) { | ||||||
67 | print("i = ", i, "\n"); | ||||||
68 | } | ||||||
69 | %> | ||||||
70 | |||||||
71 | # Output | ||||||
72 | i = 0 | ||||||
73 | i = 1 | ||||||
74 | i = 2 | ||||||
75 | |||||||
76 | C |
||||||
77 | HTML-escape every individual variable. (See L for more details.) | ||||||
78 | |||||||
79 | # Perl | ||||||
80 | my $ejs = EJS::Template->new(escape => 'html'); # Set default escape type | ||||||
81 | |||||||
82 | $ejs->process('sample.ejs', { | ||||||
83 | address => '"Foo Bar" |
||||||
84 | message => ' Hello, World! ', # not to be escaped |
||||||
85 | }); | ||||||
86 | |||||||
87 | # EJS ('<%=' escapes the value, while '<%:raw=' does *not*) | ||||||
88 | <%= address %> |
||||||
89 | |
||||||
90 | <%:raw= message %> | ||||||
91 | |||||||
92 | |||||||
93 | # Output | ||||||
94 | "Foo Bar" <foo.bar@example.com> |
||||||
95 | |
||||||
96 | Hello, World! |
||||||
97 | |||||||
98 | |||||||
99 | Extra white spaces around C<< <% >> and C<< %> >> are appropriately trimmed | ||||||
100 | so that the result output will look fairly clean intuitively. | ||||||
101 | |||||||
102 | |
||||||
103 | <% for (...) { %> | ||||||
104 | |
||||||
105 | <% } %> | ||||||
106 | |||||||
107 | |||||||
108 | In the above example, the C |
||||||
109 | In order to make the result HTML look clean, these whitespaces are automatically removed. | ||||||
110 | See L for more details. | ||||||
111 | |||||||
112 | |||||||
113 | =head1 DESCRIPTION | ||||||
114 | |||||||
115 | EJS is a template with JavaScript code embedded, and this module provides a | ||||||
116 | template engine to generate output from EJS templates. | ||||||
117 | |||||||
118 | It can be used as a general-purpose template engine to generate text documents, | ||||||
119 | configurations, source code, etc. | ||||||
120 | For web applications, EJS can be used as a template of HTML. | ||||||
121 | |||||||
122 | EJS is suitable when template authors should not embed potentially dangerous | ||||||
123 | code such as file system manipulations, command executions, and database | ||||||
124 | connections, while at the same time, they can still utilize JavaScript as a | ||||||
125 | well-established programming language. | ||||||
126 | |||||||
127 | Especially for web applications, there are several different approaches to | ||||||
128 | implement similar EJS functionality, such as parsing EJS and/or executing | ||||||
129 | JavaScript on the server side or the browser side. | ||||||
130 | This module implements both parsing and executing on the server side from that | ||||||
131 | perspective. | ||||||
132 | |||||||
133 | =head1 METHODS | ||||||
134 | |||||||
135 | =head2 new | ||||||
136 | |||||||
137 | Creates an C |
||||||
138 | |||||||
139 | Usage: | ||||||
140 | |||||||
141 | my $ejs = EJS::Template->new( [NAME => VALUE, ...] ); | ||||||
142 | |||||||
143 | Available configurations are as below: | ||||||
144 | |||||||
145 | =over 4 | ||||||
146 | |||||||
147 | =item * escape => ESCAPE_TYPE | ||||||
148 | |||||||
149 | Sets the default escape type for all the interpolation tags (C<< <%=...%> >>). | ||||||
150 | |||||||
151 | Possible values are: C<'raw'> (default), C<'html'>, C<'xml'>, C<'uri'>, and | ||||||
152 | C<'quote'>. See L for more details. | ||||||
153 | |||||||
154 | =item * engine => ENGINE_CLASS | ||||||
155 | |||||||
156 | Sets the JavaScript engine class. | ||||||
157 | See L for more details. | ||||||
158 | |||||||
159 | =back | ||||||
160 | |||||||
161 | =cut | ||||||
162 | |||||||
163 | sub new { | ||||||
164 | 74 | 74 | 1 | 854 | my ($class, %config) = @_; | ||
165 | 74 | 133 | my $self = {map {$_ => $config{$_}} @CONFIG_KEYS, qw(parser executor)}; | ||||
296 | 524 | ||||||
166 | 74 | 203 | return bless $self, $class; | ||||
167 | } | ||||||
168 | |||||||
169 | =head2 process | ||||||
170 | |||||||
171 | Usage: | ||||||
172 | |||||||
173 | # Simple | ||||||
174 | EJS::Template->process([INPUT [, VARIABLES [, OUTPUT ] ] ]); | ||||||
175 | |||||||
176 | # Custom | ||||||
177 | my $ejs = EJS::Template->new(...); | ||||||
178 | $ejs->process([INPUT [, VARIABLES [, OUTPUT ] ] ]); | ||||||
179 | |||||||
180 | INPUT is the EJS source (default: STDIN). | ||||||
181 | It can be either a string (as a file path), a string ref (as a source text), or | ||||||
182 | an open file handle. | ||||||
183 | |||||||
184 | VARIABLES is a hash ref that maps variable names to values, which are made | ||||||
185 | available in the JavaScript code (default: an empty hash). | ||||||
186 | The values of VARIABLES can be a nested structure of hashes, arrays, strings, | ||||||
187 | numbers, and/or subroutine refs. | ||||||
188 | A function (subroutine) named C |
||||||
189 | overwritten in VARIABLES. | ||||||
190 | |||||||
191 | OUTPUT is where the final result is written out (default: STDOUT). | ||||||
192 | It can be either a string (as a file path), a string ref (as a source text), or | ||||||
193 | an open file handle. | ||||||
194 | |||||||
195 | Examples: | ||||||
196 | |||||||
197 | # Reads the file 'source.ejs' and prints the result to STDOUT | ||||||
198 | EJS::Template->process('source.ejs', {name => 'World'}); | ||||||
199 | |||||||
200 | # Reads STDIN as the EJS source and writes the result to the file 'output.txt' | ||||||
201 | EJS::Template->process(\*STDIN, {name => 'World'}, 'output.txt'); | ||||||
202 | |||||||
203 | # Parses the EJS source text and stores the result to the variable $out | ||||||
204 | my $out; | ||||||
205 | EJS::Template->process(\'Hello <%=name%>', {name => 'World'}, \$out); | ||||||
206 | |||||||
207 | =cut | ||||||
208 | |||||||
209 | sub process { | ||||||
210 | 63 | 63 | 1 | 1303 | my ($self, $input, $variables, $output) = @_; | ||
211 | 63 | 100 | 167 | local $context = ref $self ? $self : $self->new(); | |||
212 | |||||||
213 | 63 | 67 | eval { | ||||
214 | 63 | 58 | my $parsed; | ||||
215 | 63 | 154 | $context->parse($input, \$parsed); | ||||
216 | 63 | 140 | $context->execute(\$parsed, $variables, $output); | ||||
217 | }; | ||||||
218 | |||||||
219 | 63 | 50 | 134 | die $@ if $@; | |||
220 | 63 | 220 | return 1; | ||||
221 | } | ||||||
222 | |||||||
223 | =head2 apply | ||||||
224 | |||||||
225 | Usage: | ||||||
226 | |||||||
227 | EJS::Template->apply(INPUT_TEXT [, VARIABLES]) | ||||||
228 | |||||||
229 | Example: | ||||||
230 | |||||||
231 | my $text = EJS::Template->apply('Hello <%= name %>', {name => 'World'}); | ||||||
232 | print $text; | ||||||
233 | |||||||
234 | This method serves as a syntax sugar for the C |
||||||
235 | text-to-text conversion. | ||||||
236 | |||||||
237 | =cut | ||||||
238 | |||||||
239 | sub apply { | ||||||
240 | 1 | 1 | 1 | 72297 | my ($self, $input, $variables) = @_; | ||
241 | 1 | 50 | 7 | local $context = ref $self ? $self : $self->new(); | |||
242 | 1 | 1 | my $output; | ||||
243 | |||||||
244 | 1 | 1 | eval { | ||||
245 | 1 | 3 | $context->process(\$input, $variables, \$output); | ||||
246 | }; | ||||||
247 | |||||||
248 | 1 | 50 | 2 | die $@ if $@; | |||
249 | 1 | 12 | return $output; | ||||
250 | } | ||||||
251 | |||||||
252 | =head2 parse | ||||||
253 | |||||||
254 | Usage: | ||||||
255 | |||||||
256 | EJS::Template->parse([INPUT [, OUTPUT ] ]); | ||||||
257 | |||||||
258 | INPUT is the EJS source, and OUTPUT is a JavaScript code, | ||||||
259 | which can then be executed to generate the final output. | ||||||
260 | (See C |
||||||
261 | |||||||
262 | The parsed code can be stored in a file as an intermediate code, | ||||||
263 | and can be executed at a later time. | ||||||
264 | |||||||
265 | The semantics of INPUT and OUTPUT types are similar to C |
||||||
266 | |||||||
267 | =cut | ||||||
268 | |||||||
269 | sub parse { | ||||||
270 | 83 | 83 | 1 | 107 | my ($self, $input, $parsed_output) = @_; | ||
271 | 83 | 100 | 173 | local $context = ref $self ? $self : $self->new(); | |||
272 | |||||||
273 | 83 | 76 | eval { | ||||
274 | 83 | 182 | $context->parser->parse($input, $parsed_output); | ||||
275 | }; | ||||||
276 | |||||||
277 | 83 | 50 | 537 | die $@ if $@; | |||
278 | 83 | 168 | return 1; | ||||
279 | } | ||||||
280 | |||||||
281 | =head2 execute | ||||||
282 | |||||||
283 | Usage: | ||||||
284 | |||||||
285 | EJS::Template->execute([INPUT [, VARIABLES [, OUTPUT ] ] ]); | ||||||
286 | |||||||
287 | INPUT is a JavaScript code generated by C |
||||||
288 | and OUTPUT is the final result. | ||||||
289 | |||||||
290 | The semantics of INPUT and OUTPUT types are similar to C |
||||||
291 | |||||||
292 | =cut | ||||||
293 | |||||||
294 | sub execute { | ||||||
295 | 63 | 63 | 1 | 89 | my ($self, $parsed_input, $variables, $output) = @_; | ||
296 | 63 | 50 | 127 | local $context = ref $self ? $self : $self->new(); | |||
297 | |||||||
298 | 63 | 61 | eval { | ||||
299 | 63 | 126 | $context->executor->execute($parsed_input, $variables, $output); | ||||
300 | }; | ||||||
301 | |||||||
302 | 63 | 50 | 143 | die $@ if $@; | |||
303 | 63 | 145 | return 1; | ||||
304 | } | ||||||
305 | |||||||
306 | |||||||
307 | =head2 context | ||||||
308 | |||||||
309 | Usage: | ||||||
310 | |||||||
311 | EJS::Template->context; | ||||||
312 | |||||||
313 | Retrieves the C |
||||||
314 | |||||||
315 | It is useful when retrieving the object from within the JavaScript execution. | ||||||
316 | |||||||
317 | my $template = EJS::Template->new(); | ||||||
318 | |||||||
319 | $template->process(\*STDIN, { | ||||||
320 | callFromJS => sub { | ||||||
321 | my $context = EJS::Template->context; | ||||||
322 | # In this case, $context is the same as $template. | ||||||
323 | ... | ||||||
324 | } | ||||||
325 | }); | ||||||
326 | |||||||
327 | The above example is trivial because the current context can also be easily referenced | ||||||
328 | from the outer C<$template> variable via the closure. | ||||||
329 | However, even if this subroutine is defined in some other places, the current template | ||||||
330 | object can always be retrieved via this call. | ||||||
331 | |||||||
332 | =cut | ||||||
333 | |||||||
334 | sub context { | ||||||
335 | 8 | 8 | 1 | 17438 | my $class = shift; | ||
336 | 8 | 33 | 37 | $class = ref($class) || $class; | |||
337 | 8 | 33 | 36 | return $context ||= $class->new; | |||
338 | } | ||||||
339 | |||||||
340 | =head2 parser | ||||||
341 | |||||||
342 | Gets or sets an C |
||||||
343 | |||||||
344 | # Getter | ||||||
345 | $template->parser; | ||||||
346 | |||||||
347 | # Setter | ||||||
348 | $template->parser(EJS::Template::Parser->new($template)); | ||||||
349 | |||||||
350 | =cut | ||||||
351 | |||||||
352 | sub parser { | ||||||
353 | 83 | 83 | 1 | 71 | my $self = shift; | ||
354 | 83 | 50 | 167 | $self = $self->context unless ref $self; | |||
355 | |||||||
356 | 83 | 50 | 151 | if (@_) { | |||
357 | 0 | 0 | my $old = $self->{parser}; | ||||
358 | 0 | 0 | $self->{parser} = shift; | ||||
359 | 0 | 0 | return $old; | ||||
360 | } else { | ||||||
361 | 83 | 66 | 522 | return $self->{parser} ||= EJS::Template::Parser->new($self); | |||
362 | } | ||||||
363 | } | ||||||
364 | |||||||
365 | =head2 executor | ||||||
366 | |||||||
367 | Gets or sets an C |
||||||
368 | |||||||
369 | # Getter | ||||||
370 | $template->executor; | ||||||
371 | |||||||
372 | # Setter | ||||||
373 | $template->executor(EJS::Template::Executor->new($template)); | ||||||
374 | |||||||
375 | =cut | ||||||
376 | |||||||
377 | sub executor { | ||||||
378 | 74 | 74 | 1 | 74 | my $self = shift; | ||
379 | 74 | 50 | 146 | $self = $self->context unless ref $self; | |||
380 | |||||||
381 | 74 | 50 | 150 | if (@_) { | |||
382 | 0 | 0 | my $old = $self->{executor}; | ||||
383 | 0 | 0 | $self->{executor} = shift; | ||||
384 | 0 | 0 | return $old; | ||||
385 | } else { | ||||||
386 | 74 | 66 | 478 | return $self->{executor} ||= EJS::Template::Executor->new($self); | |||
387 | } | ||||||
388 | } | ||||||
389 | |||||||
390 | =head2 bind | ||||||
391 | |||||||
392 | Binds name-value pairs to the associated JavaScript engine. | ||||||
393 | |||||||
394 | $template->bind({name1 => $value1}); | ||||||
395 | $template->apply('<% print("name1 = ", name1) %>'); | ||||||
396 | |||||||
397 | =cut | ||||||
398 | |||||||
399 | sub bind { | ||||||
400 | 5 | 5 | 1 | 4555 | my $self = shift; | ||
401 | 5 | 50 | 15 | $self = $self->context unless ref $self; | |||
402 | 5 | 12 | return $self->executor->adapter->bind(@_); | ||||
403 | } | ||||||
404 | |||||||
405 | =head2 eval | ||||||
406 | |||||||
407 | Invokes the C |
||||||
408 | |||||||
409 | $template->eval('new Date().toString()'); | ||||||
410 | |||||||
411 | =cut | ||||||
412 | |||||||
413 | sub eval { | ||||||
414 | 1 | 1 | 1 | 6 | my $self = shift; | ||
415 | 1 | 50 | 4 | $self = $self->context unless ref $self; | |||
416 | 1 | 3 | return $self->executor->adapter->eval(@_); | ||||
417 | } | ||||||
418 | |||||||
419 | =head2 print | ||||||
420 | |||||||
421 | Prints text to the current output target. | ||||||
422 | |||||||
423 | $template->print('Hello, World!'); | ||||||
424 | |||||||
425 | This method can only be called under the execution context, usually from | ||||||
426 | within a subroutine invoked by JavaScript. | ||||||
427 | |||||||
428 | $template->process('example.ejs', { | ||||||
429 | callFromJS => sub { | ||||||
430 | $template->print('Hello, World!'); | ||||||
431 | } | ||||||
432 | }); | ||||||
433 | |||||||
434 | =cut | ||||||
435 | |||||||
436 | sub print { | ||||||
437 | 5 | 5 | 1 | 3970 | my $self = shift; | ||
438 | 5 | 50 | 15 | $self = $self->context unless ref $self; | |||
439 | 5 | 9 | return $self->executor->print(@_); | ||||
440 | } | ||||||
441 | |||||||
442 | |||||||
443 | =head1 DETAILS | ||||||
444 | |||||||
445 | =head2 Auto-escaping | ||||||
446 | |||||||
447 | C |
||||||
448 | method. | ||||||
449 | |||||||
450 | EJS::Template->new(escape => 'html')->process(...); | ||||||
451 | |||||||
452 | If the C |
||||||
453 | HTML-escaped automatically. | ||||||
454 | |||||||
455 | # Input | ||||||
456 | <% var text = "x < y < z"; %> | ||||||
457 | <%= text %> | ||||||
458 | |||||||
459 | # Output | ||||||
460 | x < y < z | ||||||
461 | |||||||
462 | In case a raw HTML needs to be embedded without escaping, it can be annotated like this: | ||||||
463 | |||||||
464 | <%:raw= text %> | ||||||
465 | |||||||
466 | In addition, the following escape types are available in a similar manner | ||||||
467 | (both for the C<< escape => >> config or in each individual tag C<< <%=...%> >>): | ||||||
468 | |||||||
469 | =over 4 | ||||||
470 | |||||||
471 | =item * html | ||||||
472 | |||||||
473 | <%:html= plainText %> | ||||||
474 | |||||||
475 | =item * xml | ||||||
476 | |||||||
477 | |
||||||
478 | |||||||
479 | =item * uri | ||||||
480 | |||||||
481 | Link | ||||||
482 | |||||||
483 | =item * quote | ||||||
484 | |||||||
485 | |||||||
488 | |||||||
489 | =item * raw | ||||||
490 | |||||||
491 | <%:raw= htmlText %> |
||||||
492 | |||||||
493 | =back | ||||||
494 | |||||||
495 | =head2 Trimming white spaces | ||||||
496 | |||||||
497 | C |
||||||
498 | (but not around C<< <%=...%> >>). | ||||||
499 | |||||||
500 | It helps the template author generate a fairly well-formatted output: | ||||||
501 | |||||||
502 | EJS: | ||||||
503 | |||||||
504 | |
||||||
505 | <% for (var i = 1; i <= 5; i++) { %> | ||||||
506 | |
||||||
507 | <% if (i % 2 == 1) { %> | ||||||
508 | <%=i%> x <%=i%> = <%=i * i%> | ||||||
509 | <% } %> | ||||||
510 | |||||||
511 | <% } %> | ||||||
512 | |||||||
513 | |||||||
514 | Output: | ||||||
515 | |||||||
516 | |
||||||
517 | |
||||||
518 | 1 x 1 = 1 | ||||||
519 | |||||||
520 | |
||||||
521 | 3 x 3 = 9 | ||||||
522 | |||||||
523 | |
||||||
524 | 5 x 5 = 25 | ||||||
525 | |||||||
526 | |||||||
527 | |||||||
528 | Note: If no white spaces were trimmed, the result output would look much more ugly, | ||||||
529 | because of extra indent spaces and line breaks around C<< <% for (...) %> >>, | ||||||
530 | C<< <% if (...) %> >>, etc. | ||||||
531 | |||||||
532 | The trimming occurs only when C<< <% >> is at the beginning of a line with any indent | ||||||
533 | spaces, and its corresponding C<< %> >> is at the end of the same or another line | ||||||
534 | with any trailing spaces. | ||||||
535 | |||||||
536 | When the above trimming condition is met, | ||||||
537 | any white spaces to the left of C<< <% >> (not including any line breaks) and | ||||||
538 | any white spaces to the right of C<< %> >> (including the line break) are trimmed. | ||||||
539 | |||||||
540 | =head2 Data conversion between Perl and EJS | ||||||
541 | |||||||
542 | In the current version, the data conversion is limited to basic types | ||||||
543 | (strings, numbers, hashes, arrays, and functions), although arbitrarily nested | ||||||
544 | structures are allowed. | ||||||
545 | |||||||
546 | EJS::Template->process('sample.ejs', { | ||||||
547 | name => 'World', | ||||||
548 | hash => {foo => 123, bar => 456, baz => [7, 8, 9]}, | ||||||
549 | array => ['a'..'z'], | ||||||
550 | square => sub { | ||||||
551 | my $value = shift; | ||||||
552 | return $value * $value; | ||||||
553 | } | ||||||
554 | }); | ||||||
555 | |||||||
556 | If a blessed reference in Perl is passed to EJS, it is converted into a basic type. | ||||||
557 | |||||||
558 | If a Perl subroutine is invoked from inside EJS, the types of the arguments depend | ||||||
559 | on the JavaScript engine that is in use internally (See L). | ||||||
560 | |||||||
561 | # Perl | ||||||
562 | sub printRefs { | ||||||
563 | print(ref($_) || '(scalar)', "\n") foreach @_; | ||||||
564 | } | ||||||
565 | |||||||
566 | EJS::Template->process(\< |
||||||
567 | <% | ||||||
568 | printRefs( | ||||||
569 | 'str', | ||||||
570 | 123, | ||||||
571 | [4, 5, 6], | ||||||
572 | {x: 7, y: 8}, | ||||||
573 | function () {return 90} | ||||||
574 | ); | ||||||
575 | %> | ||||||
576 | END | ||||||
577 | |||||||
578 | # Output with JavaScript::V8 | ||||||
579 | (scalar) | ||||||
580 | (scalar) | ||||||
581 | ARRAY | ||||||
582 | HASH | ||||||
583 | CODE | ||||||
584 | |||||||
585 | # Output with JE | ||||||
586 | JE::String | ||||||
587 | JE::Number | ||||||
588 | JE::Object::Array | ||||||
589 | JE::Object | ||||||
590 | JE::Object::Function | ||||||
591 | |||||||
592 | For portability, it is recommended to keep data types as simple as possible | ||||||
593 | when data is passed between Perl and EJS. | ||||||
594 | |||||||
595 | =head2 JavaScript engines | ||||||
596 | |||||||
597 | C |
||||||
598 | the below: | ||||||
599 | |||||||
600 | =over 4 | ||||||
601 | |||||||
602 | =item * V8 (same engine as Google Chrome): | ||||||
603 | |||||||
604 | L |
||||||
605 | |||||||
606 | =item * SpiderMonkey (same engine as Mozilla Firefox): | ||||||
607 | |||||||
608 | L |
||||||
609 | |||||||
610 | L |
||||||
611 | |||||||
612 | =item * Pure Perl implementation | ||||||
613 | |||||||
614 | L |
||||||
615 | |||||||
616 | =back | ||||||
617 | |||||||
618 | It is also possible to specify a particular engine: | ||||||
619 | |||||||
620 | EJS::Template->new(engine => 'JE')->process(...); | ||||||
621 | EJS::Template->new(engine => 'JavaScript::SpiderMonkey')->process(...); | ||||||
622 | |||||||
623 | =head2 Including another EJS file | ||||||
624 | |||||||
625 | Although this module does not provide the C |
||||||
626 | it can be implemented as below, depending on the use case. | ||||||
627 | |||||||
628 | # Perl | ||||||
629 | my $template = EJS::Template->new({escape => 'html'}); | ||||||
630 | $template->process('index.html.ejs', { | ||||||
631 | include => sub { | ||||||
632 | my ($path) = @_; | ||||||
633 | # TODO: Validate $path to avoid reading arbitrary files | ||||||
634 | my $context = EJS::Template->context; | ||||||
635 | $context->process($path); | ||||||
636 | } | ||||||
637 | }); | ||||||
638 | |||||||
639 | # EJS (index.html.ejs) | ||||||
640 | <% | ||||||
641 | include('header.html.ejs'); | ||||||
642 | include('content.html.ejs'); | ||||||
643 | include('footer.html.ejs'); | ||||||
644 | %> | ||||||
645 | |||||||
646 | =head2 Unicode/UTF-8 | ||||||
647 | |||||||
648 | Some JavaScript engines correctly translate Unicode strings in Perl (utf8 flag turned on) | ||||||
649 | into Unicode strings in JavaScript, and vice versa. | ||||||
650 | |||||||
651 | # Perl to JavaScript | ||||||
652 | use utf8; | ||||||
653 | my $input = "{Unicode string}"; | ||||||
654 | EJS::Template->process(\'<%=str%>', {str => $input}); | ||||||
655 | |||||||
656 | # JavaScript to Perl | ||||||
657 | my $output; | ||||||
658 | EJS::Template->process(\'<%func("{Unicode string}")%>', { | ||||||
659 | func => sub {$output = shift} | ||||||
660 | }); | ||||||
661 | |||||||
662 | Currently, C |
||||||
663 | seem to have issues with Unicode as below. | ||||||
664 | |||||||
665 | If Unicode strings in Perl are passed to JavaScript, then the strings are unexpectedly | ||||||
666 | encoded as UTF-8, where each character in JavaScript strings corresponds to each byte | ||||||
667 | of UTF-8 characters. | ||||||
668 | |||||||
669 | If Unicode strings in JavaScript are passed to Perl, then the strings may | ||||||
670 | become corrupted. | ||||||
671 | |||||||
672 | |||||||
673 | =head1 AUTHOR | ||||||
674 | |||||||
675 | Mahiro Ando, C<< |
||||||
676 | |||||||
677 | =head1 BUGS | ||||||
678 | |||||||
679 | Please report any bugs or feature requests to C |
||||||
680 | the web interface at L |
||||||
681 | automatically be notified of progress on your bug as I make changes. | ||||||
682 | |||||||
683 | =head1 SUPPORT | ||||||
684 | |||||||
685 | You can find documentation for this module with the perldoc command. | ||||||
686 | |||||||
687 | perldoc EJS::Template | ||||||
688 | |||||||
689 | You can also look for information at: | ||||||
690 | |||||||
691 | =over 4 | ||||||
692 | |||||||
693 | =item * GitHub repository (report bugs here) | ||||||
694 | |||||||
695 | L |
||||||
696 | |||||||
697 | =item * RT: CPAN's request tracker (report bugs here, alternatively) | ||||||
698 | |||||||
699 | L |
||||||
700 | |||||||
701 | =item * AnnoCPAN: Annotated CPAN documentation | ||||||
702 | |||||||
703 | L |
||||||
704 | |||||||
705 | =item * CPAN Ratings | ||||||
706 | |||||||
707 | L |
||||||
708 | |||||||
709 | =item * Search CPAN | ||||||
710 | |||||||
711 | L |
||||||
712 | |||||||
713 | =back | ||||||
714 | |||||||
715 | =head1 ACKNOWLEDGEMENTS | ||||||
716 | |||||||
717 | Many thanks to authors of JavaScript engines for making them available, | ||||||
718 | and to authors of those in the SEE ALSO section for giving me | ||||||
719 | ideas and inspirations. | ||||||
720 | |||||||
721 | =head1 SEE ALSO | ||||||
722 | |||||||
723 | =over 4 | ||||||
724 | |||||||
725 | =item * Template Toolkit (a.k.a. TT) | ||||||
726 | |||||||
727 | L |
||||||
728 | |||||||
729 | =item * JavaScript Template engine based on TT2 | ||||||
730 | |||||||
731 | L |
||||||
732 | |||||||
733 | =item * Browser-side EJS | ||||||
734 | |||||||
735 | L |
||||||
736 | |||||||
737 | L |
||||||
738 | |||||||
739 | =item * EJS for Ruby: | ||||||
740 | |||||||
741 | L |
||||||
742 | |||||||
743 | =back | ||||||
744 | |||||||
745 | =head1 LICENSE AND COPYRIGHT | ||||||
746 | |||||||
747 | Copyright 2012 Mahiro Ando. | ||||||
748 | |||||||
749 | This program is free software; you can redistribute it and/or modify it | ||||||
750 | under the terms of either: the GNU General Public License as published | ||||||
751 | by the Free Software Foundation; or the Artistic License. | ||||||
752 | |||||||
753 | See http://dev.perl.org/licenses/ for more information. | ||||||
754 | |||||||
755 | =cut | ||||||
756 | |||||||
757 | 1; # End of EJS::Template |