| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
package UR::Singleton; |
|
3
|
|
|
|
|
|
|
|
|
4
|
337
|
|
|
337
|
|
2483
|
use strict; |
|
|
289
|
|
|
|
|
533
|
|
|
|
278
|
|
|
|
|
8252
|
|
|
5
|
278
|
|
|
284
|
|
1087
|
use warnings; |
|
|
273
|
|
|
|
|
388
|
|
|
|
269
|
|
|
|
|
79039
|
|
|
6
|
|
|
|
|
|
|
require UR; |
|
7
|
|
|
|
|
|
|
our $VERSION = "0.46"; # UR $VERSION; |
|
8
|
|
|
|
|
|
|
|
|
9
|
|
|
|
|
|
|
UR::Object::Type->define( |
|
10
|
|
|
|
|
|
|
class_name => 'UR::Singleton', |
|
11
|
|
|
|
|
|
|
is => ['UR::Object'], |
|
12
|
|
|
|
|
|
|
is_abstract => 1, |
|
13
|
|
|
|
|
|
|
); |
|
14
|
|
|
|
|
|
|
|
|
15
|
|
|
|
|
|
|
sub id { |
|
16
|
15355
|
|
|
15356
|
1
|
29258
|
my $self = shift; |
|
17
|
15355
|
100
|
|
|
|
47758
|
return (ref $self ? $self->SUPER::id(@_) : $self); |
|
18
|
|
|
|
|
|
|
} |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub _init_subclass { |
|
21
|
2022
|
|
|
2022
|
|
4023
|
my $class_name = shift; |
|
22
|
2022
|
|
|
|
|
6844
|
my $class_meta_object = $class_name->__meta__; |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
# Write into the class's namespace the correct singleton overrides |
|
25
|
|
|
|
|
|
|
# to standard UR::Object methods. |
|
26
|
|
|
|
|
|
|
|
|
27
|
2022
|
|
|
|
|
2838
|
my $src; |
|
28
|
2022
|
100
|
|
|
|
16705
|
if ($class_meta_object->is_abstract) { |
|
29
|
799
|
|
|
|
|
6577
|
$src = qq|sub ${class_name}::_singleton_object { Carp::confess("${class_name} is an abstract singleton! Select a concrete sub-class.") }| |
|
30
|
|
|
|
|
|
|
. "\n" |
|
31
|
|
|
|
|
|
|
. qq|sub ${class_name}::_singleton_class_name { Carp::confess("${class_name} is an abstract singleton! Select a concrete sub-class.") }| |
|
32
|
|
|
|
|
|
|
. "\n" |
|
33
|
|
|
|
|
|
|
. qq|sub ${class_name}::_load { shift->_abstract_load(\@_) }| |
|
34
|
|
|
|
|
|
|
} |
|
35
|
|
|
|
|
|
|
else { |
|
36
|
1223
|
|
|
|
|
13529
|
$src = qq|sub ${class_name}::_singleton_object { \$${class_name}::singleton or shift->_concrete_load() }| |
|
37
|
|
|
|
|
|
|
. "\n" |
|
38
|
|
|
|
|
|
|
. qq|sub ${class_name}::_singleton_class_name { '${class_name}' }| |
|
39
|
|
|
|
|
|
|
. "\n" |
|
40
|
|
|
|
|
|
|
. qq|sub ${class_name}::_load { shift->_concrete_load(\@_) }| |
|
41
|
|
|
|
|
|
|
. "\n" |
|
42
|
|
|
|
|
|
|
. qq|sub ${class_name}::get { shift->_concrete_get(\@_) }| |
|
43
|
|
|
|
|
|
|
. "\n" |
|
44
|
|
|
|
|
|
|
. qq|sub ${class_name}::is_loaded { shift->_concrete_is_loaded(\@_) }| |
|
45
|
|
|
|
|
|
|
; |
|
46
|
|
|
|
|
|
|
} |
|
47
|
|
|
|
|
|
|
|
|
48
|
2022
|
100
|
|
48
|
1
|
247607
|
eval $src; |
|
|
48
|
100
|
|
41
|
1
|
466
|
|
|
|
41
|
0
|
|
56
|
1
|
377
|
|
|
|
56
|
|
|
36
|
1
|
537
|
|
|
|
36
|
|
|
2
|
1
|
344
|
|
|
|
2
|
|
|
35
|
1
|
4
|
|
|
|
35
|
|
|
1
|
1
|
65
|
|
|
|
1
|
|
|
0
|
1
|
2
|
|
|
|
0
|
|
|
5664
|
1
|
0
|
|
|
|
5664
|
|
|
3809
|
1
|
20769
|
|
|
|
3809
|
|
|
4512
|
1
|
13911
|
|
|
|
4512
|
|
|
4415
|
1
|
16933
|
|
|
|
4415
|
|
|
8140
|
1
|
16185
|
|
|
|
8140
|
|
|
6918
|
0
|
110399
|
|
|
|
6918
|
|
|
5670
|
0
|
97378
|
|
|
|
5670
|
|
|
4821
|
|
95056
|
|
|
|
4821
|
|
|
1
|
|
74177
|
|
|
|
1
|
|
|
0
|
|
196
|
|
|
|
0
|
|
|
149
|
|
|
|
|
|
0
|
|
|
2
|
|
|
|
|
|
|
|
|
2
|
|
|
|
|
|
|
|
|
0
|
|
|
|
|
49
|
2022
|
50
|
|
|
|
6679
|
Carp::confess($@) if $@; |
|
50
|
|
|
|
|
|
|
|
|
51
|
2022
|
|
|
|
|
8054
|
return 1; |
|
52
|
|
|
|
|
|
|
} |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# Abstract singletons havd a different load() method than concrete ones. |
|
55
|
|
|
|
|
|
|
# We could do this with forking logic, but since many of the concrete methods |
|
56
|
|
|
|
|
|
|
# get non-default handling, it's more efficient to do it this way. |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
sub _abstract_load { |
|
59
|
4478
|
|
|
4478
|
|
42157
|
my $class = shift; |
|
60
|
3059
|
|
|
|
|
21290
|
my $bx = $class->define_boolexpr(@_); |
|
61
|
3056
|
|
|
|
|
22560
|
my $id = $bx->value_for_id; |
|
62
|
750
|
100
|
|
|
|
7323
|
unless (defined $id) { |
|
63
|
267
|
|
|
270
|
|
1424
|
use Data::Dumper; |
|
|
266
|
|
|
|
|
353
|
|
|
|
266
|
|
|
|
|
68934
|
|
|
64
|
18
|
|
|
|
|
477
|
my $params = { $bx->params_list }; |
|
65
|
48
|
|
|
|
|
188
|
Carp::confess("Cannot load a singleton ($class) except by specific identity. " . Dumper($params)); |
|
66
|
|
|
|
|
|
|
} |
|
67
|
278
|
|
|
|
|
2109
|
my $subclass_name = $class->_resolve_subclass_name_for_id($id); |
|
68
|
266
|
|
|
266
|
|
94653
|
eval "use $subclass_name"; |
|
|
266
|
|
|
|
|
609
|
|
|
|
266
|
|
|
|
|
2662
|
|
|
|
280
|
|
|
|
|
19425
|
|
|
69
|
280
|
100
|
|
|
|
4454
|
if ($@) { |
|
70
|
0
|
|
|
|
|
0
|
undef $@; |
|
71
|
0
|
|
|
|
|
0
|
return; |
|
72
|
|
|
|
|
|
|
} |
|
73
|
426
|
|
|
|
|
5405
|
return $subclass_name->get(); |
|
74
|
|
|
|
|
|
|
} |
|
75
|
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# Concrete singletons have overrides to the most basic acccessors to |
|
77
|
|
|
|
|
|
|
# accomplish class/object duality smoothly. |
|
78
|
|
|
|
|
|
|
|
|
79
|
|
|
|
|
|
|
sub _concrete_get { |
|
80
|
14781
|
100
|
66
|
17561
|
|
47429
|
if (@_ == 1 or (@_ == 2 and $_[0] eq $_[1])) { |
|
|
|
|
66
|
|
|
|
|
|
81
|
14780
|
|
|
|
|
216865
|
my $self = $_[0]->_singleton_object; |
|
82
|
14778
|
100
|
|
|
|
74046
|
return $self if $self; |
|
83
|
|
|
|
|
|
|
} |
|
84
|
1
|
|
|
|
|
3
|
return shift->_concrete_load(@_); |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
sub _concrete_is_loaded { |
|
88
|
1174
|
100
|
33
|
3953
|
|
4837
|
if (@_ == 1 or (@_ == 2 and $_[0] eq $_[1])) { |
|
|
|
|
66
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
|
90
|
1173
|
|
|
|
|
23180
|
my $self = $_[0]->_singleton_object; |
|
91
|
1173
|
100
|
|
|
|
4050
|
return $self if $self; |
|
92
|
|
|
|
|
|
|
} |
|
93
|
1
|
|
|
|
|
6
|
return shift->SUPER::is_loaded(@_); |
|
94
|
|
|
|
|
|
|
} |
|
95
|
|
|
|
|
|
|
|
|
96
|
|
|
|
|
|
|
sub _concrete_load { |
|
97
|
1174
|
|
|
1647
|
|
2451
|
my $class = shift; |
|
98
|
|
|
|
|
|
|
|
|
99
|
1174
|
|
66
|
|
|
5112
|
$class = ref($class) || $class; |
|
100
|
266
|
|
|
275
|
|
1166
|
no strict 'refs'; |
|
|
266
|
|
|
|
|
367
|
|
|
|
266
|
|
|
|
|
60742
|
|
|
101
|
1174
|
|
|
|
|
1578
|
my $varref = \${ $class . "::singleton" }; |
|
|
1174
|
|
|
|
|
4720
|
|
|
102
|
1174
|
100
|
|
|
|
3197
|
unless ($$varref) { |
|
103
|
1173
|
|
|
|
|
7155
|
my $id = $class->_resolve_id_for_subclass_name($class); |
|
104
|
|
|
|
|
|
|
|
|
105
|
1173
|
|
|
|
|
4341
|
my $class_object = $class->__meta__; |
|
106
|
1173
|
|
|
|
|
9823
|
my @prop_names = $class_object->all_property_names; |
|
107
|
1173
|
|
|
|
|
1775
|
my %default_values; |
|
108
|
1173
|
|
|
|
|
2221
|
foreach my $prop_name ( @prop_names ) { |
|
109
|
5364
|
|
|
|
|
13150
|
my $prop = $class_object->property_meta_for_name($prop_name); |
|
110
|
5364
|
100
|
|
|
|
11598
|
next unless $prop; |
|
111
|
5364
|
|
|
|
|
8366
|
my $val = $prop->{'default_value'}; |
|
112
|
5364
|
100
|
|
|
|
11536
|
next unless defined $val; |
|
113
|
2187
|
|
|
|
|
4498
|
$default_values{$prop_name} = $val; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
1173
|
|
|
|
|
8093
|
$$varref = $UR::Context::current->_construct_object($class,%default_values, id => $id); |
|
117
|
1173
|
|
|
|
|
17281
|
$$varref->{db_committed} = { %$$varref }; |
|
118
|
1173
|
|
|
|
|
9202
|
$$varref->__signal_change__("load"); |
|
119
|
1173
|
|
|
|
|
5236
|
Scalar::Util::weaken($$varref); |
|
120
|
|
|
|
|
|
|
} |
|
121
|
1174
|
|
|
|
|
8814
|
my $self = $class->_concrete_is_loaded(@_); |
|
122
|
1174
|
100
|
|
|
|
3015
|
return unless $self; |
|
123
|
1173
|
100
|
|
|
|
6979
|
unless ($self->init) { |
|
124
|
0
|
|
|
|
|
0
|
Carp::confess("Failed to initialize singleton $class!"); |
|
125
|
|
|
|
|
|
|
} |
|
126
|
1173
|
|
|
|
|
2442
|
return $self; |
|
127
|
|
|
|
|
|
|
} |
|
128
|
|
|
|
|
|
|
|
|
129
|
|
|
|
|
|
|
# This is implemented in the singleton to do any post-load processing. |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
sub init { |
|
132
|
1173
|
|
|
1191
|
1
|
3061
|
return 1; |
|
133
|
|
|
|
|
|
|
} |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
# All singletons require special deletion logic since they keep a |
|
136
|
|
|
|
|
|
|
#weakened reference to the singleton. |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
sub delete { |
|
139
|
1
|
|
|
49
|
1
|
400
|
my $self = shift; |
|
140
|
1
|
|
|
|
|
8
|
my $class = $self->class; |
|
141
|
1
|
|
|
|
|
5
|
$self->SUPER::delete(); |
|
142
|
266
|
|
|
270
|
|
1142
|
no strict 'refs'; |
|
|
266
|
|
|
|
|
392
|
|
|
|
266
|
|
|
|
|
48447
|
|
|
143
|
1
|
50
|
|
|
|
1
|
${ $class . "::singleton" } = undef if ${ $class . "::singleton" } eq $self; |
|
|
1
|
|
|
|
|
3
|
|
|
|
1
|
|
|
|
|
11
|
|
|
144
|
1
|
|
|
|
|
7
|
return $self; |
|
145
|
|
|
|
|
|
|
} |
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
# In most cases, the id is the class name itself, but this is not necessary. |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
sub _resolve_subclass_name_for_id { |
|
150
|
278
|
|
|
279
|
|
599
|
my $class = shift; |
|
151
|
278
|
|
|
|
|
503
|
my $id = shift; |
|
152
|
278
|
|
|
|
|
1045
|
return $id; |
|
153
|
|
|
|
|
|
|
} |
|
154
|
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
sub _resolve_id_for_subclass_name { |
|
156
|
1173
|
|
|
1176
|
|
1926
|
my $class = shift; |
|
157
|
1173
|
|
|
|
|
1720
|
my $subclass_name = shift; |
|
158
|
1173
|
|
|
|
|
2150
|
return $subclass_name; |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
sub create { |
|
162
|
1
|
|
|
4
|
1
|
364
|
my $class = shift; |
|
163
|
1
|
|
|
|
|
11
|
my $bx = $class->define_boolexpr(@_); |
|
164
|
1
|
|
|
|
|
4
|
my $id = $bx->value_for_id; |
|
165
|
1
|
100
|
|
|
|
3
|
unless (defined $id) { |
|
166
|
0
|
|
|
|
|
0
|
Carp::confess("No singleton ID class specified for constructor?"); |
|
167
|
|
|
|
|
|
|
} |
|
168
|
1
|
|
|
|
|
9
|
my $subclass = $class->_resolve_subclass_name_for_id($id); |
|
169
|
1
|
|
|
|
|
73
|
eval "use $subclass"; |
|
170
|
1
|
100
|
|
|
|
10
|
unless ($subclass->isa(__PACKAGE__)) { |
|
171
|
0
|
|
|
|
|
0
|
eval '@' . $subclass . "::ISA = ('" . __PACKAGE__ . "')"; |
|
172
|
|
|
|
|
|
|
} |
|
173
|
|
|
|
|
|
|
|
|
174
|
1
|
|
|
|
|
7
|
return $subclass->_concrete_get(); |
|
175
|
|
|
|
|
|
|
} |
|
176
|
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
|
|
178
|
|
|
|
|
|
|
1; |
|
179
|
|
|
|
|
|
|
|
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=pod |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=head1 NAME |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
UR::Singleton - Abstract class for implementing singleton objects |
|
186
|
|
|
|
|
|
|
|
|
187
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
package MyApp::SomeClass; |
|
190
|
|
|
|
|
|
|
use UR; |
|
191
|
|
|
|
|
|
|
class MyApp::SomeClass { |
|
192
|
|
|
|
|
|
|
is => 'UR::Singleton', |
|
193
|
|
|
|
|
|
|
has => [ |
|
194
|
|
|
|
|
|
|
foo => { is => 'Number' }, |
|
195
|
|
|
|
|
|
|
] |
|
196
|
|
|
|
|
|
|
}; |
|
197
|
|
|
|
|
|
|
|
|
198
|
|
|
|
|
|
|
$obj = MyApp::SomeClass->get(); |
|
199
|
|
|
|
|
|
|
$obj->foo(1); |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
202
|
|
|
|
|
|
|
|
|
203
|
|
|
|
|
|
|
This class provides the infrastructure for singleton classes. Singletons |
|
204
|
|
|
|
|
|
|
are classes of which there can only be one instance, and that instance's ID |
|
205
|
|
|
|
|
|
|
is the class name. |
|
206
|
|
|
|
|
|
|
|
|
207
|
|
|
|
|
|
|
If a class inherits from UR::Singleton, it overrides the default |
|
208
|
|
|
|
|
|
|
implementation of C and C in UR::Object with code that |
|
209
|
|
|
|
|
|
|
fabricates an appropriate object the first time it's needed. |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
Singletons are most often used as one of the parent classes for data sources |
|
212
|
|
|
|
|
|
|
within a Namespace. This makes it convienent to refer to them using only |
|
213
|
|
|
|
|
|
|
their name, as in a class definition. |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
=head1 METHODS |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=over 4 |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
=item _singleton_object |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
$obj = Class::Name->_singleton_object; |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
$obj = $obj->_singleton_object; |
|
224
|
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
Returns the object instance whether it is called as a class or object method. |
|
226
|
|
|
|
|
|
|
|
|
227
|
|
|
|
|
|
|
=item _singleton_class_name |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
$class_name = Class::Name->_singleton_class_name; |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
$class_name = $obj->_singleton_class_name; |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
Returns the class name whether it is called as a class or object method. |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
=back |
|
236
|
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
238
|
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
UR::Object |
|
240
|
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
=cut |