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