File Coverage

blib/lib/JavaScript/Writer.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package JavaScript::Writer;
2              
3 19     19   325866 use warnings;
  19         51  
  19         552  
4 19     19   90 use strict;
  19         30  
  19         513  
5              
6 19     19   472 use 5.008;
  19         61  
  19         854  
7 19     19   50651 use self;
  0            
  0            
8              
9             use overload
10             '<<' => sub {
11             no warnings;
12             push @{ self->{statements} }, { code => args };
13             return self;
14             },
15             '""' => \&as_string;
16              
17             use JSON::Syck;
18              
19             our $VERSION = '0.3.1';
20              
21             use Sub::Exporter -setup => {
22             exports => ['js'],
23             groups => {
24             default => [ -all ],
25             }
26             };
27              
28             my $base;
29              
30             sub _js {
31             # Return the top-most $_[0] JavaScript::Writer object in stack.
32             my $level = 2;
33             my @c = ();
34             my $js;
35             while ( $level < 10 && (!defined($c[3]) || $c[3] eq '(eval)') ) {
36             @c = do {
37             package DB;
38             @DB::args = ();
39             caller($level);
40             };
41             $level++;
42              
43             if (ref($DB::args[0]) eq 'JavaScript::Writer') {
44             $js = $DB::args[0] ;
45             last;
46             }
47             }
48             return $js;
49             }
50              
51             sub js {
52             my $js = _js();
53              
54             my ($obj) = @_;
55             if (defined $js) {
56             $js->{object} = $obj if defined $obj;
57             return $js;
58             }
59              
60             $base = JavaScript::Writer->new() unless defined $base;
61             $base->{object} = $obj if defined $obj;
62             return $base;
63             }
64              
65             sub new {
66             if (ref(self)) {
67             if (defined $base) {
68             self->{statements} = [];
69             return self;
70             }
71             return __PACKAGE__->new;
72             }
73              
74             $self = bless { args }, $self;
75             $self->{statements} = [];
76             return $self;
77             }
78              
79             sub call {
80             my ($function, @function_args) = @args;
81             my $eoc = !defined wantarray;
82             push @{self->{statements}},{
83             object => delete self->{object} || undef,
84             call => $function,
85             args => \@function_args,
86             end_of_call_chain => $eoc
87             };
88             return self;
89             }
90              
91             sub __in_jsw_packages__ {
92             my $level = 0;
93             my @c = caller(++$level);
94             while ( @c > 0 ) {
95             return 1 if defined $c[0] && index($c[0], __PACKAGE__) == 0;
96             @c = caller(++$level);
97             }
98             return 0;
99             }
100              
101             sub append {
102             if ( __in_jsw_packages__ ) {
103             push @{ self->{statements} }, { code => args };
104             return self;
105             }
106              
107             return self->call("append", args);
108             }
109              
110             sub object {
111             self->{object} = args[0];
112             return self;
113             }
114              
115             sub latter {
116             my ($cb) = args;
117              
118             my $timeout = delete self->{object};
119             $timeout =~ s/ms$//;
120             $timeout =~ s/s$/000/;
121              
122             my $jsf = JavaScript::Writer::Function->new;
123             $jsf->body($cb);
124              
125             self->append("setTimeout($jsf, $timeout)");
126             return self;
127             }
128              
129             use JavaScript::Writer::Var;
130              
131             sub let {
132             my %vars = args;
133             my $code = "";
134             while (my ($var, $value) = each %vars) {
135             self->var($var, $value);
136             }
137             return self;
138             }
139              
140             sub var {
141             my ($var, $value) = @args;
142             my $s = "";
143              
144             if (!defined $value) {
145             $s = "var $var;";
146             }
147             elsif (ref($value) eq 'ARRAY' || ref($value) eq 'HASH' || !ref($value) ) {
148             $s = "var $var = " . $self->obj_as_string($value) . ";"
149             }
150             elsif (ref($value) eq 'CODE') {
151             $s = "var $var = " . $self->function($value);
152             }
153             elsif (ref($value) =~ /^JavaScript::Writer/) {
154             $s = "var $var = " . $value->as_string();
155             }
156             elsif (ref($value) eq 'REF') {
157             my $j = $self->new;
158             $j->var($var => $$value);
159             $s = $j->as_string;
160             }
161             elsif (ref($value) eq 'SCALAR') {
162             if (defined $$value) {
163             my $v = $self->obj_as_string($value);
164              
165             $s = "var $var = $v;";
166             }
167             else {
168             $s = "var $var;";
169             }
170              
171             eval {
172             JavaScript::Writer::Var->new(
173             $value,
174             {
175             name => $var,
176             jsw => $self
177             }
178             );
179             };
180              
181             }
182              
183             $self->append($s);
184             return $self;
185             }
186              
187             use JavaScript::Writer::Block;
188              
189             sub do {
190             my ($block) = args;
191             my $condition = delete self->{object};
192             my $b = JavaScript::Writer::Block->new;
193             $b->body($block);
194             self->append("if($condition)${b}", delimiter => "" );
195             }
196              
197             sub while {
198             my ($condition, $block) = @args;
199             my $b = JavaScript::Writer::Block->new;
200             $b->body($block);
201             $self->append("while(${condition})${b}", , delimiter => "" );
202             }
203              
204             use JavaScript::Writer::Function;
205              
206             sub function {
207             return JavaScript::Writer::Function->new(args);
208             }
209              
210             sub obj_as_string {
211             my ($obj) = @args;
212              
213             if (ref($obj) eq 'CODE') {
214             return self->function($obj);
215             }
216             elsif (ref($obj) =~ /^JavaScript::Writer/) {
217             return $obj->as_string
218             }
219             elsif (ref($obj) eq "SCALAR") {
220             return $$obj
221             }
222             elsif (ref($obj) eq 'ARRAY') {
223             my @ret = map {
224             self->obj_as_string($_)
225             } @$obj;
226              
227             return "[" . join(",", @ret) . "]";
228             }
229             elsif (ref($obj) eq 'HASH') {
230             my %ret;
231             while (my ($k, $v) = each %$obj) {
232             $ret{$k} = self->obj_as_string($v)
233             }
234             return "{" . join (",", map { JSON::Syck::Dump($_) . ":" . $ret{$_} } sort keys %ret) . "}";
235             }
236             else {
237             return JSON::Syck::Dump($obj)
238             }
239             }
240              
241             sub as_string {
242             my $ret = "";
243              
244             for (@{self->{statements}}) {
245             my $delimiter =
246             defined($_->{delimiter}) ? $_->{delimiter} : ($_->{end_of_call_chain} ? ";" : ".");
247             if (my $f = $_->{call}) {
248              
249             my $args = $_->{args};
250             $ret .= ($_->{object} ? "$_->{object}." : "" ) .
251             "$f(" .
252             join(",",
253             map {
254             self->obj_as_string( $_ );
255             } @$args
256             ) . ")" . $delimiter
257             }
258             elsif (my $c = $_->{code}) {
259             $delimiter = defined $_->{delimiter} ? $_->{delimiter} : ";";
260             $c .= $delimiter unless $c =~ /$delimiter\s*$/s;
261             $ret .= $c;
262             }
263             }
264             return $ret;
265             }
266              
267             require JavaScript::Writer::BasicHelpers;
268              
269             {
270             my $sn = 0;
271             sub as_html {
272             my (%param) = @args;
273             $sn++;
274              
275             my $id = "javascript-writer-$$-$sn";
276              
277             if ($param{closure}) {
278             my $j = JavaScript::Writer->new;
279             my $self_code = $self->as_string;
280             $j->closure(
281             this => \ "document.getElementById('$id')",
282             body => sub {
283             js->append( $self_code );
284             }
285             );
286             return qq{}
287             }
288             return qq{};
289             }
290             }
291              
292             our $AUTOLOAD;
293             sub AUTOLOAD {
294             my $function = $AUTOLOAD;
295             $function =~ s/.*:://;
296              
297             return self->call($function, args);
298             }
299              
300             1; # Magic true value required at end of module
301              
302             __END__