| 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 |