File Coverage

lib/UR/DeletedRef.pm
Criterion Covered Total %
statement 32 40 80.0
branch 5 10 50.0
condition n/a
subroutine 7 9 77.7
pod 0 2 0.0
total 44 61 72.1


line stmt bran cond sub pod time code
1             package UR::DeletedRef;
2              
3 266     266   919 use strict;
  266         314  
  266         6300  
4 266     266   832 use warnings;
  266         290  
  266         9921  
5             require UR;
6              
7             BEGIN {
8             # this is to workaround a Perl bug where the overload magic flag is not updated
9             # for references with a different RV (which happens anytime you do "my $object"
10             # https://rt.perl.org/rt3/Public/Bug/Display.html?id=9472
11 266 50   266   65896 if ($^V lt v5.8.9) {
12 0         0 eval "use overload fallback => 1";
13             };
14             };
15              
16             our $VERSION = "0.46"; # UR $VERSION;
17              
18             our $all_objects_deleted = {};
19              
20             sub bury {
21 2305     2305 0 2111 my $class = shift;
22              
23 2305         2602 for my $object (@_) {
24 2305 50       3558 if ($ENV{'UR_DEBUG_OBJECT_RELEASE'}) {
25 0         0 print STDERR "MEM BURY object $object class ",$object->class," id ",$object->id,"\n";
26             }
27 2305         2184 my $original_class = ref($object);
28 2305         3412 my $original_id = $object->id;
29              
30 2305         14678 %$object = (original_class => ref($object), original_data => {%$object});
31 2305         3388 bless $object, 'UR::DeletedRef';
32              
33 2305         3570 $all_objects_deleted->{$original_class}->{$original_id} = $object;
34 2305         5184 Scalar::Util::weaken($all_objects_deleted->{$original_class}->{$original_id});
35             }
36              
37 2305         2954 return 1;
38             }
39              
40             sub resurrect {
41 14 50   14 0 39 shift unless (ref($_[0]));
42              
43 14         23 foreach my $object (@_) {
44 14         27 my $original_class = $object->{'original_class'};
45 14         51 bless $object, $original_class;
46 14         13 %$object = (%{$object->{original_data}});
  14         106  
47 14         64 my $id = $object->id;
48 14         28 delete $all_objects_deleted->{$original_class}->{$id};
49 14 50       73 $object->resurrect_object if ($object->can('resurrect_object'));
50             }
51              
52 14         848 return 1;
53             }
54              
55 266     266   1173 use Data::Dumper;
  266         334  
  266         48781  
56              
57             sub AUTOLOAD {
58 0     0   0 our $AUTOLOAD;
59 0         0 my $method = $AUTOLOAD;
60 0         0 $method =~ s/^.*:://g;
61 0         0 Carp::croak("Attempt to use a reference to an object which has been deleted. A call was made to method '$method'\nRessurrect it first.\n" . Dumper($_[0]));
62             }
63              
64             sub __rollback__ {
65 0     0   0 return 1;
66             }
67              
68             sub DESTROY {
69 2305 50   2305   26468 if ($ENV{'UR_DEBUG_OBJECT_RELEASE'}) {
70 0         0 print STDERR "MEM DESTROY deletedref $_[0]\n";
71             }
72 2305         12051 delete $all_objects_deleted->{"$_[0]"};
73             }
74              
75             1;
76              
77              
78             =pod
79              
80             =head1 NAME
81              
82             UR::DeletedRef - Represents an instance of a no-longer-existent object
83              
84             =head1 SYNOPSIS
85              
86             my $obj = Some::Class->get(123);
87            
88             $obj->delete;
89             print ref($obj),"\n"; # prints 'UR::DeletedRef'
90             $obj->some_method(); # generates an exception through Carp::confess
91              
92             $obj->resurrect;
93             print ref($obj),"\n"; # prints 'Some::Class'
94              
95             =head1 DESCRIPTION
96              
97             Object instances become UR::DeletedRefs when some part of the application
98             calls delete() or unload() on them, meaning that they no longer exist
99             in that Context. The extant object reference is turned into a UR::DeletedRef
100             so that if that same reference is used in any capacity later in the program,
101             it will generate an exception through its AUTOLOAD to prevent using it by
102             mistake.
103              
104             Note that UR::DeletedRef instances are different than Ghost objects. When a
105             UR-based object is deleted through delete(), a new Ghost object reference is
106             created from the data in the old object, and the old object reference is
107             re-blessed as a UR::DeletedRef. Any variables still referencing the original
108             object now hold a reference to this UR::DeletedRef. The Ghost object can be
109             retrieved by issuing a get() against the Ghost class.
110              
111             Objects unloaded from the Context using unload(), or indirectly by rolling-back
112             a transaction which triggers unload of objects loaded during the transaction,
113             are also turned into UR::DeletedRefs.
114              
115             You aren't likely to encounter UR::DeletedRefs in normal use. What usually
116             happens is that an object will be deleted with delete() (or unload()), the
117             lexical variable pointing to the DeletedRef will soon go out of scope and
118             the DeletedRef will then be garbage-colelcted.
119              
120             =head1 SEE ALSO
121              
122             UR::Object, UR::Object::Ghost, UR::Context
123              
124             =cut
125