File Coverage

blib/lib/EJS/Template/JSAdapter.pm
Criterion Covered Total %
statement 29 39 74.3
branch 10 20 50.0
condition n/a
subroutine 6 8 75.0
pod 5 5 100.0
total 50 72 69.4


line stmt bran cond sub pod time code
1 8     8   502 use 5.006;
  8         19  
2 8     8   24 use strict;
  8         7  
  8         518  
3 8     8   23 use warnings;
  8         8  
  8         2446  
4              
5             =head1 NAME
6              
7             EJS::Template::JSAdapter - JavaScript engine adapter for EJS::Template
8              
9             =cut
10              
11             package EJS::Template::JSAdapter;
12              
13             =head1 Variables
14              
15             =head2 @SUPPORTED_ENGINES
16              
17             Supported JavaScript engine classes
18              
19             =over 4
20              
21             =item * L
22              
23             =item * L
24              
25             =item * L
26              
27             =item * L
28              
29             =back
30              
31             =cut
32              
33             our @SUPPORTED_ENGINES = qw(
34             JavaScript::V8
35             JavaScript
36             JavaScript::SpiderMonkey
37             JE
38             );
39              
40             my $default_adapter_class;
41              
42             =head1 Methods
43              
44             =head2 create
45              
46             Instantiates a JavaScript engine adapter object.
47              
48             my $adapter = EJS::Template::JSAdapter->create();
49              
50             If no argument is passed, an engine is selected from the available ones.
51              
52             An explicit engine can also be specified. E.g.
53              
54             my $je_engine = EJS::Template::JSAdapter->create('JE');
55             my $v8_engine = EJS::Template::JSAdapter->create('JavaScript::V8');
56              
57             =cut
58              
59             sub create {
60 57     57 1 77695 my ($class, $engine) = @_;
61            
62 57 100       137 if ($engine) {
    100          
63 29         55 my $adapter_class = $class.'::'.$engine;
64 29         1683 eval "require $adapter_class";
65            
66 29 50       112 if ($@) {
67 0         0 $adapter_class = $engine;
68 0         0 eval "require $adapter_class";
69 0 0       0 die $@ if $@;
70             }
71            
72 29         126 return $adapter_class->new();
73             } elsif ($default_adapter_class) {
74 23         114 return $default_adapter_class->new();
75             } else {
76 5         13 for my $candidate (@SUPPORTED_ENGINES) {
77 20         876 eval "require $candidate";
78 20 100       364670 next if $@;
79            
80 5         23 my $adapter_class = $class.'::'.$candidate;
81 5         275 eval "require $adapter_class";
82 5 50       30 next if $@;
83            
84 5         10 $default_adapter_class = $adapter_class;
85 5         32 return $adapter_class->new();
86             }
87            
88 0         0 die "No JavaScript engine modules are found. ".
89             "Consider to install JavaScript::V8";
90             }
91             }
92              
93             =head2 new
94              
95             Creates an adapter object.
96              
97             This method should be overridden, and a property named 'engine' is expected to be set up.
98              
99             package Some::Extended::JSAdapter;
100             use base 'EJS::Template::JSAdapter';
101            
102             sub new {
103             my ($class) = @_;
104             my $engine = Some::Underlying::JavaScript::Engine->new();
105             return bless {engine => $engine}, $class;
106             }
107              
108             =cut
109              
110             sub new {
111 0     0 1 0 my ($class) = @_;
112 0         0 return bless {engine => undef}, $class;
113             }
114              
115             =head2 engine
116              
117             Retrieves the underlying engine object.
118              
119             =cut
120              
121             sub engine {
122 253     253 1 238 my ($self) = @_;
123 253         502 return $self->{engine};
124             }
125              
126             =head2 bind
127              
128             Binds variable mapping to JavaScript objects.
129              
130             This method should be overridden in a way that it can be invoked like this:
131              
132             $engine->bind({
133             varname1 => $object1,
134             funcname2 => sub {...},
135             ...
136             });
137              
138             =cut
139              
140             sub bind {
141 0     0 1 0 my ($self, $variables) = @_;
142            
143 0 0       0 if (my $engine = $self->engine) {
144 0 0       0 if ($engine->can('bind')) {
145 0         0 return $engine->bind($variables);
146             }
147             }
148             }
149              
150             =head2 eval
151              
152             Evaluates a JavaScript code.
153              
154             This method should be overridden in a way that it can be invoked like this:
155              
156             $engine->eval('print("ok\n")');
157              
158             =cut
159              
160             sub eval {
161 62     62 1 77 my ($self) = @_;
162            
163 62 50       118 if (my $engine = $self->engine) {
164 62 50       564 if ($engine->can('eval')) {
165 62         173 return $engine->eval($_[1]);
166             }
167             }
168             }
169              
170             =head1 SEE ALSO
171              
172             =over 4
173              
174             =item * L
175              
176             =back
177              
178             =cut
179              
180             1;