File Coverage

blib/lib/JE/Object.pm
Criterion Covered Total %
statement 197 209 94.2
branch 93 104 89.4
condition 38 50 76.0
subroutine 46 49 93.8
pod 8 26 30.7
total 382 438 87.2


line stmt bran cond sub pod time code
1             package JE::Object;
2              
3             # This has to come before any pragmas and sub declarations.
4 181     181 0 243 sub evall { my $global = shift; my $r = eval 'local *_;' . shift;
  181         15287  
5 181 50       728 $@ and die; $r }
  181         519  
6              
7             our $VERSION = '0.064';
8              
9 101     101   45638 use strict;
  101         148  
  101         3221  
10 101     101   390 use warnings;
  101         695  
  101         5979  
11              
12             use overload fallback => 1,
13             '%{}'=> \&_get_tie,
14             '""' => 'to_string',
15             '0+' => 'to_number',
16             # cmp => sub { "$_[0]" cmp $_[1] },
17 101     101   46902 bool => sub { 1 };
  101     74141   75878  
  101         1130  
  74141         162845  
18              
19 101     101   9606 use Scalar::Util qw'refaddr blessed';
  101         129  
  101         5551  
20 101     101   482 use List::Util 'first';
  101         121  
  101         5020  
21 101     101   415 use B 'svref_2object';
  101         122  
  101         231884  
22             #use Data::Dumper;
23              
24              
25             require JE::Code;
26             require JE::Object::Error::TypeError;
27             require JE::Object::Function;
28             require JE::Boolean;
29             require JE::String;
30              
31             import JE::Code 'add_line_number';
32             sub add_line_number;
33              
34             sub in_list {
35 231     231 0 289 my $str = shift;
36 231   100     1714 shift eq $str and return 1 while @_;
37 219         896 !1;
38             }
39              
40              
41             =head1 NAME
42              
43             JE::Object - Base class for all JavaScript objects
44              
45             =head1 SYNOPSIS
46              
47             use JE;
48             use JE::Object;
49              
50             $j = new JE;
51              
52             $obj = new JE::Object $j;
53              
54             $obj->prop('property1', $new_value); # sets the property
55             $obj->prop('property1'); # returns $new_value;
56             $obj->{property1} = $new_value; # or use it as a hash
57             $obj->{property1}; # ref like this
58              
59             $obj->keys; # returns a list of the names of enumerable property
60             keys %$obj;
61              
62             $obj->delete('property_name');
63             delete $obj->{property_name};
64              
65             $obj->method('method_name', 'arg1', 'arg2');
66             # calls a method with the given arguments
67              
68             $obj->value ; # returns a value useful in Perl (a hashref)
69              
70             "$obj"; # "[object Object]" -- same as $obj->to_string->value
71             0+$obj"; # nan -- same as $obj->to_number->value
72             # etc.
73              
74             =head1 DESCRIPTION
75              
76             This module implements JavaScript objects for JE. It serves as a base
77             class
78             for all other JavaScript objects.
79              
80             A JavaScript object is an associative array, the elements of which are
81             its properties. A method is a property that happens to be an instance
82             of the
83             C class (C).
84              
85             JE::Object objects can be used in Perl as a number, string or boolean. The
86             result will be the same as in JavaScript. The C<%{}> (hashref) operator is
87             also overloaded and returns a hash that can be used to modify the object.
88             See L<"USING AN OBJECT AS A HASH">.
89              
90             See also L for descriptions of most of the methods. Only what
91             is specific to JE::Object is explained here.
92              
93             =head1 METHODS
94              
95             =over 4
96              
97             =item $obj = JE::Object->new( $global_obj )
98              
99             =item $obj = JE::Object->new( $global_obj, $value )
100              
101             =item $obj = JE::Object->new( $global_obj, \%options )
102              
103             This class method constructs and returns a new JavaScript object, unless
104             C<$value> is
105             already a JS object, in which case it just returns it. The behaviour is
106             the
107             same as the C constructor in JavaScript.
108              
109             The C<%options> are as follows:
110              
111             prototype the object to be used as the prototype for this
112             object (Object.prototype is the default)
113             value the value to be turned into an object
114              
115             C only applies when C is omitted, undef, undefined
116             or null.
117              
118             To convert a hash into an object, you can use the hash ref syntax like
119             this:
120              
121             new JE::Object $j, { value => \%hash }
122              
123             Though it may be easier to write:
124              
125             $j->upgrade(\%hash)
126              
127             The former is what C itself uses.
128              
129             =cut
130              
131             # ~~~ Perhaps I should eliminate the hash ref syntax and have new()
132             # check to see if $j->exists($class->class), and use that as the
133             # prototype. That would make the other constructors simpler, but would
134             # it make it harder to control JE and customise host objects?
135              
136             sub new {
137 19491     19491 1 24416 my($class, $global, $value) = @_;
138              
139 19491 100 100     52148 if (defined blessed $value
140             and can $value 'to_object') {
141 9         24 return to_object $value;
142             }
143            
144 19482         16497 my $p;
145             my %hash;
146 0         0 my %opts;
147              
148 19482 100       62421 ref $value eq 'HASH' and (%opts = %$value), $value = $opts{value};
149            
150 19482         21295 local $@;
151 19482 100 66     45093 if (!defined $value || !defined eval{$value->value} && $@ eq '') {
  7 50 66     54  
152 19479 100       47814 $p = exists $opts{prototype} ? $opts{prototype}
153             : $global->prototype_for("Object");
154             }
155             elsif(ref $value eq 'HASH') {
156 3         8 %hash = %$value;
157 3         10 $p = $global->prototype_for("Object");
158             }
159             else {
160 0         0 return $global->upgrade($value);
161             }
162              
163 19482         99506 my $self =
164             bless \{ prototype => $p,
165             global => $global,
166             props => \%hash,
167             keys => [keys %hash] }, $class;
168              
169 19482 50       35436 $JE::Destroyer && JE::Destroyer'register($self);
170              
171 19482         52646 $self;
172             }
173              
174             sub destroy { # not DESTROY; called by JE::Destroyer
175 0     0 0 0 undef ${$_[0]};
  0         0  
176             }
177              
178              
179             =item $obj->new_function($name, sub { ... })
180              
181             =item $obj->new_function(sub { ... })
182              
183             This creates and returns a new function object. If $name is given,
184             it will become a property of the object. The function is enumerable, like
185             C I in web browsers.
186              
187             For more ways to create functions, see L.
188              
189             =cut
190              
191             sub new_function {
192 707     707 1 4064 my $self = shift;
193 707 50       1234 my $f = JE::Object::Function->new({
194             scope => $self->global,
195             function => pop,
196             function_args => ['args'],
197             @_ ? (name => $_[0]) : ()
198             });
199 707 50       3172 @_ and $self->prop({
200             name => shift,
201             value=>$f,
202             });
203 707         1741 $f;
204             }
205              
206              
207              
208              
209             =item $obj->new_method($name, sub { ... })
210              
211             =item $obj->new_method(sub { ... })
212              
213             This is the same as C, except that the subroutine's first
214             argument will be the object with which the function is called, and that the
215             property created will not be enumerable. This allows one to add methods to
216             C, for instance, without making every for-in loop list
217             that method.
218              
219             For more ways to create functions, see L.
220              
221             =cut
222              
223             sub new_method {
224 24     24 1 34 my $self = shift;
225 24 50       46 my $f = JE::Object::Function->new({
226             scope => $self->global,
227             function => pop,
228             function_args => ['this','args'],
229             @_ ? (name => $_[0]) : ()
230             });
231 24 50       140 @_ and $self->prop({
232             name => shift,
233             value=>$f,
234             dontenum=>1
235             });
236 24         106 $f;
237             }
238              
239             =item $obj->prop( $name )
240              
241             =item $obj->prop( $name => $value )
242              
243             =item $obj->prop({ ... })
244              
245             See C for the first two uses.
246              
247             When the C method is called with a hash ref as its argument, the
248             prototype chain is I searched.
249             The elements of the hash are as follows:
250              
251             name property name
252             value new value
253             dontenum whether this property is unenumerable
254             dontdel whether this property is undeletable
255             readonly whether this property is read-only
256             fetch subroutine called when the property is fetched
257             store subroutine called when the property is set
258             autoload see below
259              
260             If C, C or C is given, the attribute in
261             question will be set.
262             If C is given, the value of the property will be set, regardless of
263             the attributes.
264              
265             C and C, if specified, must be subroutines for
266             fetching/setting the value of the property. The 'fetch' subroutine will be
267             called with ($object, $storage_space) as the arguments, where
268             C<$storage_space> is a hash key inside the object that the two subroutines
269             can use for storing the value (they can ignore it if they like). The
270             'store' subroutine will be call with
271             ($object, $new_value, $storage_space) as
272             the arguments. Values assigned to the storage space from within these
273             routines are I
274             upgraded, neither is the return value of C. C and C do
275             not necessarily have to go
276             together. If you only specify C, then the value will be set as
277             usual, but C will be able to mangle the value when it is retrieved.
278             Likewise, if you only specify C, the value will be retrieved the
279             usual way, so you can use this for validating or normalising the assigned
280             value, for
281             instance. B Currently, a simple scalar or unblessed coderef in the
282             storage space will cause autoloading, but that is subject to change.
283              
284             C can be a string or a coderef. It will be called/evalled the
285             first time the property is accessed (accessing it with a hash ref as
286             described here does not count). If it is a string, it will be
287             evaluated in the calling package (see warning below), in a scope that has a
288             variable named
289             C<$global> that refers to the global object. The result will become the
290             property's value. The value returned is not currently upgraded. The behaviour when a simple scalar or unblessed reference is returned is
291             undefined. C will be
292             ignored completely if C or C is also given. B The
293             'calling package' may not be what you think it is if a subclass overrides
294             C. It may be the subclass in such cases. To be on the safe side,
295             always begin the string of code with an explicit C statement. (If
296             anyone knows of a clean solution to this, please let the author know.)
297              
298             This hash ref calling convention does not work on Array
299             objects when the property name is C or an array index (a
300             non-negative integer
301             below
302             4294967295). It does not work on String objects if the
303             property name is C.
304              
305             =cut
306              
307             sub prop {
308 164303     164303 1 222956 my ($self, $opts) = (shift, shift);
309 164303         204334 my $guts = $$self;
310              
311 164303 100       271228 if(ref $opts eq 'HASH') { # special use
312 34097         38778 my $name = $$opts{name};
313 34097         44417 for (qw< dontdel readonly >) {
314 68194 100       163474 exists $$opts{$_}
315             and $$guts{"prop_$_"}{$name} = $$opts{$_};
316             }
317              
318 34097         39794 my $props = $$guts{props};
319              
320 34097         25700 my $dontenum;
321 34097 100       54816 if(exists $$opts{dontenum}) {
    100          
322 27255 50       36744 if($$opts{dontenum}) {
323 27255         39808 @{$$guts{keys}} =
  27255         35045  
324 27255         21813 grep $_ ne $name, @{$$guts{keys}};
325             }
326             else {
327 0     0   0 push @{ $$guts{keys} }, $name
  0         0  
328 0 0       0 unless first {$_ eq $name} @{$$guts{keys}};
  0         0  
329             }
330             }
331             elsif(!exists $$props{$name}) { # new property
332 6474         5305 push @{ $$guts{keys} }, $name
  6474         11055  
333             }
334              
335 34097 100       58467 if(exists $$opts{fetch}) {
336 111         188 $$guts{fetch_handler}{$name} = $$opts{fetch};
337 111 50       257 $$props{$name} = undef if !exists $$props{$name};
338             }
339 34097 100       51704 if(exists $$opts{store}) {
340 104         163 $$guts{store_handler}{$name} = $$opts{store};
341 104 100       200 $$props{$name} = undef if !exists $$props{$name};
342             }
343 34097 100 100     53470 if(exists $$opts{value}) {
    100          
344 31393         94774 return $$props{$name} = $$opts{value};
345             }
346             elsif(!exists $$opts{fetch} && exists $$opts{autoload}) {
347 2051         1975 my $auto = $$opts{autoload};
348 2051 100       7130 $$props{$name} = ref $auto eq 'CODE' ? $auto :
349             "package " . caller() . "; $auto";
350             return # ~~~ Figure out what this should
351             # return, if anything
352 2051         4080 }
353              
354             # ~~~ what should we return if fetch is given,
355             # but not value?
356              
357 653 100       3124 return exists $$opts{fetch} ? () :
    100          
358             exists $$props{$name} ? $$props{$name} : undef;
359             }
360              
361             else { # normal use
362 130206         129256 my $name = $opts;
363 130206         156260 my $props = $$guts{props};
364 130206 100       318610 if (@_) { # we is doing a assignment
    100          
365 23506         25240 my($new_val) = shift;
366              
367 23506 100       37263 return $new_val if $self->is_readonly($name);
368              
369             # Make sure we don't change attributes if the
370             # property already exists
371 23384   100     78143 my $exists = exists $$props{$name} &&
372             defined $$props{$name};
373              
374 23384 100       53205 exists $$guts{store_handler}{$name}
375             ? $$guts{store_handler}{$name}->(
376             $self, $new_val, $$props{$name})
377             : ($$props{$name} = $new_val);
378              
379 23384 100       44897 push @{ $$guts{keys} }, $name
  2100         3348  
380             unless $exists;
381              
382 23384         76564 return $new_val;
383             }
384             elsif (exists $$props{$name}) {
385 99123 100       202499 if(exists $$guts{fetch_handler}{$name}) {
386 68         215 return $$guts{fetch_handler}{$name}-> (
387             $self, $$props{$name}
388             );
389             }
390              
391 99055         122401 my $val = $$props{$name};
392 99055 100 66     425895 ref $val eq 'CODE' ?
393             $val = $$props{$name} = &$val() :
394             defined $val && ref $val eq '' &&
395             ($val = $$props{$name} =
396             evall $$guts{global}, $val
397             );
398 99055         247899 return $val;
399             }
400             else {
401 7577         12385 my $proto = $self->prototype;
402 7577 100       16434 return $proto ?
403             $proto->prop($name) :
404             undef;
405             }
406             }
407              
408             }
409              
410              
411             sub exists { # = hasOwnProperty
412 100125     100125 0 102064 my($self,$name) = @_;
413 100125         404480 return exists $$$self{props}{$name}
414             }
415              
416              
417             sub is_readonly { # See JE::Types for a description of this.
418 26621     26621 0 31607 my ($self,$name) = (shift,@_); # leave $name in @_
419              
420 26621         27805 my $guts = $$self;
421              
422 26621         26318 my $props = $$guts{props};
423 26621 100       55156 if( exists $$props{$name}) {
424 21460         24589 my $read_only_list = $$guts{prop_readonly};
425 21460 100       74717 return exists $$read_only_list{$name} ?
426             $$read_only_list{$name} : !1;
427             }
428              
429 5161 100       6333 if(my $proto = $self->prototype) {
430 3097         4865 return $proto->is_readonly(@_);
431             }
432              
433 2064         6694 return !1;
434             }
435              
436              
437              
438              
439             sub is_enum {
440 231     231 0 363 my ($self, $name) = @_;
441 231         363 $self = $$self;
442 231         255 in_list $name, @{ $$self{keys} };
  231         800  
443             }
444              
445              
446              
447              
448             sub keys {
449 255     255 0 496 my $self = shift;
450 255         546 my $proto = $self->prototype;
451 255 100       238 @{ $$self->{keys} }, defined $proto ? $proto->keys : ();
  255         1379  
452             }
453              
454              
455              
456              
457             =item $obj->delete($property_name, $even_if_it's_undeletable)
458              
459             Deletes the property named $name, if it is deletable. If the property did
460             not exist or it was deletable, then
461             true is returned. If the property exists and could not be deleted, false
462             is returned.
463              
464             If the second argument is given and is true, the property will be deleted
465             even if it is marked is undeletable. A subclass may override this,
466             however.
467             For instance, Array and String objects always have a 'length' property
468             which cannot be deleted.
469              
470             =cut
471              
472             sub delete {
473 291     291 1 498 my ($self, $name) = @_;
474 291         437 my $guts = $$self;
475              
476 291 100       689 unless($_[2]) { # second arg means always delete
477 176         309 my $dontdel_list = $$guts{prop_dontdel};
478 176 100 66     1415 exists $$dontdel_list{$name} and $$dontdel_list{$name}
479             and return !1;
480             }
481            
482 145         353 delete $$guts{prop_dontdel }{$name};
483 145         216 delete $$guts{prop_dontenum}{$name};
484 145         222 delete $$guts{prop_readonly}{$name};
485 145         301 delete $$guts{props}{$name};
486 145         175 $$guts{keys} = [ grep $_ ne $name, @{$$guts{keys}} ];
  145         1134  
487 145         450 return 1;
488             }
489              
490              
491              
492              
493             sub method {
494 28     28 0 68 my($self,$method) = (shift,shift);
495              
496 28         65 $self->prop($method)->apply($self, $self->global->upgrade(@_));
497             }
498              
499             =item $obj->typeof
500              
501             This returns the string 'object'.
502              
503             =cut
504              
505 112     112 1 311 sub typeof { 'object' }
506              
507              
508              
509              
510             =item $obj->class
511              
512             Returns the string 'Object'.
513              
514             =cut
515              
516 440     440 1 1737 sub class { 'Object' }
517              
518              
519              
520              
521             =item $obj->value
522              
523             This returns a hash ref of the object's enumerable properties. This is a
524             copy of the object's properties. Modifying it does not modify the object
525             itself.
526              
527             =cut
528              
529             sub value {
530 1     1 1 2 my $self = shift;
531 1         4 +{ map +($_ => $self->prop($_)), $self->keys };
532             }
533              
534             *TO_JSON=*value;
535              
536              
537              
538              
539             sub id {
540 145523     145523 0 308147 refaddr shift;
541             }
542              
543 1359     1359 0 4414 sub primitive { !1 };
544              
545             sub prototype {
546 15840 100   15840 0 22295 @_ > 1 ? (${+shift}->{prototype} = $_[1]) : ${+shift}->{prototype};
  469         3912  
  15371         32979  
547             }
548              
549              
550              
551              
552             sub to_primitive {
553 985     985 0 1425 my($self, $hint) = @_;
554              
555 985         1853 my @methods = ('valueOf','toString');
556 985 100 100     3940 defined $hint && $hint eq 'string' and @methods = reverse @methods;
557              
558 985         1022 my $method; my $prim;
559 985         1527 for (@methods) {
560 1325 100       2462 defined($method = $self->prop($_)) || next;
561 1313 100       3774 ($prim = $method->apply($self))->primitive || next;
562 971         3530 return $prim;
563             }
564              
565             die new JE::Object::Error::TypeError $self->global,
566             add_line_number "An object of type " .
567 8   33     14 (eval {$self->class} || ref $self) .
568             " cannot be converted to a primitive";
569             }
570              
571              
572              
573              
574             sub to_boolean {
575 42     42 0 582 JE::Boolean->new( $${+shift}{global}, 1 );
  42         177  
576             }
577              
578             sub to_string {
579 324     324 0 7343 shift->to_primitive('string')->to_string;
580             }
581              
582              
583             sub to_number {
584 406     406 0 1921 shift->to_primitive('number')->to_number;
585             }
586              
587 1902     1902 0 6993 sub to_object { $_[0] }
588              
589 1644     1644 0 1399 sub global { ${+shift}->{global} }
  1644         6280  
590              
591             =back
592              
593             =cut
594              
595              
596              
597              
598             #----------- PRIIVATE ROUTIES ---------------#
599              
600             # _init_proto takes the Object prototype (Object.prototype) as its sole
601             # arg and adds all the default properties thereto.
602              
603             sub _init_proto {
604 106     106   180 my $proto = shift;
605 106         247 my $global = $$proto->{global};
606              
607             # E 15.2.4
608              
609 106         354 $proto->prop({
610             dontenum => 1,
611             name => 'constructor',
612             value => $global->prop('Object'),
613             });
614              
615             my $toString_sub = sub {
616 566     566   744 my $self = shift;
617 566         1693 JE::String->new($global,
618             '[object ' . $self->class . ']');
619 106         557 };
620              
621 106         1263 $proto->prop({
622             name => 'toString',
623             value => JE::Object::Function->new({
624             scope => $global,
625             name => 'toString',
626             length => 0,
627             function_args => ['this'],
628             function => $toString_sub,
629             no_proto => 1,
630             }),
631             dontenum => 1,
632             });
633              
634             $proto->prop({
635             name => 'toLocaleString',
636             value => JE::Object::Function->new({
637             scope => $global,
638             name => 'toLocaleString',
639             length => 0,
640             function_args => ['this'],
641 7     7   36 function => sub { shift->method('toString') },
642 106         1236 no_proto => 1,
643             }),
644             dontenum => 1,
645             });
646              
647             $proto->prop({
648             name => 'valueOf',
649             value => JE::Object::Function->new({
650             scope => $global,
651             name => 'valueOf',
652             length => 0,
653             function_args => ['this'],
654 325     325   1010 function => sub { $_[0] },
655 106         1221 no_proto => 1,
656             }),
657             dontenum => 1,
658             });
659              
660             $proto->prop({
661             name => 'hasOwnProperty',
662             value => JE::Object::Function->new({
663             scope => $global,
664             name => 'hasOwnProperty',
665             argnames => ['V'],
666             function_args => ['this', 'args'],
667             function => sub {
668 24 100   24   147 JE::Boolean->new($global,
669             shift->exists(
670             defined $_[0] ? $_[0] : 'undefined'
671             )
672             );
673             },
674 106         1318 no_proto => 1,
675             }),
676             dontenum => 1,
677             });
678              
679             $proto->prop({
680             name => 'isPrototypeOf',
681             value => JE::Object::Function->new({
682             scope => $global,
683             name => 'isPrototypeOf',
684             argnames => ['V'],
685             function_args => ['this', 'args'],
686             function => sub {
687 15     15   33 my ($self, $obj) = @_;
688              
689 15 100 100     102 !defined $obj || $obj->primitive and return
690             JE::Boolean->new($global, 0);
691              
692 13         33 my $id = $self->id;
693 13         31 my $proto = $obj;
694              
695 13         29 while (defined($proto = $proto->prototype))
696             {
697 13 100       28 $proto->id eq $id and return
698             JE::Boolean->new($global, 1);
699             }
700              
701 1         5 return JE::Boolean->new($global, 0);
702             },
703 106         1576 no_proto => 1,
704             }),
705             dontenum => 1,
706             });
707              
708             $proto->prop({
709             name => 'propertyIsEnumerable',
710             value => JE::Object::Function->new({
711             scope => $global,
712             name => 'propertyIsEnumerable',
713             argnames => ['V'],
714             function_args => ['this', 'args'],
715             function => sub {
716 222 100   222   1078 return JE::Boolean->new($global,
717             shift->is_enum(
718             defined $_[0] ? $_[0] : 'undefined'
719             )
720             );
721             },
722 106         1337 no_proto => 1,
723             }),
724             dontenum => 1,
725             });
726             }
727              
728              
729              
730             #----------- TYING MAGIC ---------------#
731              
732             # I'm putting the object itself behind the tied hash, so that no new object
733             # has to be created.
734             # That means that tied %$obj returns $obj.
735              
736              
737             sub _get_tie {
738 893     893   3886 my $self = shift;
739 893         1010 my $guts = $$self;
740 893 100       1747 $$guts{tie} or tie %{ $$guts{tie} }, __PACKAGE__, $self;
  761         2584  
741 893         3600 $$guts{tie};
742             }
743              
744 764     764   1380 sub TIEHASH { $_[1] }
745 885     885   4914 sub FETCH { $_[0]->prop($_[1]) }
746             sub STORE {
747 735     735   1724 my($self, $key, $val) = @_;
748 735         1195 my $global = $self->global;
749 735 100 66     3861 if(ref $val eq 'HASH' && !blessed $val
    100 66        
      66        
      66        
      66        
      66        
750             && !%$val && svref_2object($val)->REFCNT == 2) {
751 3         11 $val = tie %$val, __PACKAGE__, __PACKAGE__->new(
752             $global);
753             } elsif (ref $val eq 'ARRAY' && !blessed $val && !@$val &&
754             svref_2object($val)->REFCNT == 2) {
755 3         21 require JE::Object::Array;
756 3         19 $val = tie @$val, 'JE::Object::Array',
757             JE::Object::Array->new($global);
758             }
759 735         1767 $self->prop($key => $global->upgrade($val))
760             }
761             #sub CLEAR { }
762             # ~~~ have yet to implement this
763             sub DELETE {
764 18     18   54 my $val = $_[0]->prop($_[1]);
765 18         60 $_[0]->delete($_[1]);
766 18         48 $val;
767             }
768 12     12   40 sub EXISTS { $_[0]->exists($_[1]) }
769 11     11   40 sub FIRSTKEY { ($_[0]->keys)[0] }
770             sub NEXTKEY {
771 29     29   57 my @keys = $_[0]->keys;
772 29         37 my $last = $_[1];
773 29         54 for (0..$#keys) {
774 58 100       116 if ($last eq $keys[$_]) {
775 29         141 return $keys[$_+1]
776             }
777             }
778              
779             # ~~~ What *should* we do if the property has been
780             # deleted?
781             # I think this means the iterator should have been reset (from the
782             # user's point of view), so we'll start from the beginning.
783              
784 0           return $keys[0];
785             }
786              
787 0     0 0   sub DDS_freeze { my $self = shift; delete $$$self{tie}; $self }
  0            
  0            
788              
789              
790             #----------- THE REST OF THE DOCUMENTATION ---------------#
791              
792             =head1 USING AN OBJECT AS A HASH
793              
794             Note first of all that C<\%$obj> is I the same as C<< $obj->value >>.
795             The C method creates a new hash containing just the enumerable
796             properties of the object and its prototypes. It's just a plain hash--no
797             ties, no magic. C<%$obj>, on the other hand, is another creature...
798              
799             C<%$obj> returns a magic hash which only lists enumerable properties
800             when you write C, but still provides access to the rest.
801              
802             Using C on this hash will check to see whether it is the object's
803             I property, and not a prototype's.
804              
805             Assignment to the hash itself currently
806             throws an error:
807              
808             %$obj = (); # no good!
809              
810             This is simply because I have not yet figured out what it should do. If
811             anyone has any ideas, please let me know.
812              
813             Autovivification works, so you can write
814              
815             $obj->{a}{b} = 3;
816              
817             and the 'a' element will be created if did not already exist. Note that,
818             if the property C exist but was undefined (from JS's point of view),
819             this throws an error.
820              
821             =begin paranoia
822              
823             One potential problem with this is that, when perl autovivifies in the
824             example
825             above, it first calls C and, when it sees that the result is not
826             defined, then calls C with C<{}> as the value. It then uses that
827             same hash that it passed to C, and does I make a second call to
828             C. This means that, for autovivification to work, the empty hash
829             that perl automatically assigns has to be tied to the new JE::Object that
830             is created. Now, the same sequence of calls to tie
831             handlers can be triggered by the following lines:
832              
833             my %h;
834             $obj->{a};
835             $h{b} = 3;
836              
837             And, of course, you don't want your %h hash transmogrified and tied to a
838             JE::Object, do you? (Normally
839             hashes and arrays are copied by STORE.) So the only feasible way (I can
840             think of) to
841             make the distinction is to use reference counts (which is what I'm using),
842             but I don't know whether they will change
843             between versions of Perl.
844              
845             =end paranoia
846              
847             =head1 INNARDS
848              
849             Each C instance is a blessed reference to a hash ref. The
850             contents of the hash
851             are as follows:
852              
853             $$self->{global} a reference to the global object
854             $$self->{props} a hash ref of properties, the values being
855             JavaScript objects
856             $$self->{prop_readonly} a hash ref with property names for the keys
857             and booleans (that indicate whether prop-
858             erties are read-only) for the values
859             $$self->{prop_dontdel} a hash ref in the same format as
860             prop_readonly that indicates whether proper-
861             ties are undeletable
862             $$self->{keys} an array of the names of enumerable
863             properties
864             $$self->{prototype} a reference to this object's prototype
865              
866             In derived classes, if you need to store extra information, begin the hash
867             keys with an underscore or use at least one capital letter in each key.
868             Such keys
869             will never be used by the
870             classes that come with the JE distribution.
871              
872             =head1 SEE ALSO
873              
874             L
875              
876             L
877              
878             =cut
879              
880              
881             1;
882