line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
# Data::Hopen::Scope - a nested key-value store |
2
|
|
|
|
|
|
|
package Data::Hopen::Scope; |
3
|
18
|
|
|
18
|
|
29344
|
use strict; |
|
18
|
|
|
|
|
42
|
|
|
18
|
|
|
|
|
546
|
|
4
|
18
|
|
|
18
|
|
101
|
use Data::Hopen::Base; |
|
18
|
|
|
|
|
40
|
|
|
18
|
|
|
|
|
116
|
|
5
|
18
|
|
|
18
|
|
4010
|
use Exporter 'import'; |
|
18
|
|
|
|
|
37
|
|
|
18
|
|
|
|
|
679
|
|
6
|
18
|
|
|
18
|
|
111
|
use Scalar::Util qw(refaddr); |
|
18
|
|
|
|
|
35
|
|
|
18
|
|
|
|
|
1400
|
|
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
our $VERSION = '0.000019'; |
9
|
|
|
|
|
|
|
|
10
|
|
|
|
|
|
|
# Class definition |
11
|
|
|
|
|
|
|
use Class::Tiny { |
12
|
18
|
|
|
|
|
173
|
outer => undef, |
13
|
|
|
|
|
|
|
local => false, |
14
|
|
|
|
|
|
|
name => 'anonymous scope', |
15
|
|
|
|
|
|
|
merge_strategy => undef, |
16
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
# Internal |
18
|
|
|
|
|
|
|
_first_set => undef, # name of the first set |
19
|
|
|
|
|
|
|
_merger_instance => undef, # A Hash::Merge instance |
20
|
18
|
|
|
18
|
|
9385
|
}; |
|
18
|
|
|
|
|
33298
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
# Static exports |
23
|
18
|
|
|
18
|
|
19437
|
use vars::i '@EXPORT_OK_PUBLIC' => [qw(is_first_only)]; |
|
18
|
|
|
|
|
4898
|
|
|
18
|
|
|
|
|
141
|
|
24
|
|
|
|
|
|
|
use vars::i { |
25
|
18
|
|
|
|
|
139
|
'@EXPORT' => [qw(FIRST_ONLY)], |
26
|
|
|
|
|
|
|
'@EXPORT_OK' => [@EXPORT_OK_PUBLIC, qw(_set0)], |
27
|
18
|
|
|
18
|
|
2018
|
}; |
|
18
|
|
|
|
|
42
|
|
28
|
18
|
|
|
|
|
161
|
use vars::i '%EXPORT_TAGS' => { |
29
|
|
|
|
|
|
|
'default' => [@EXPORT], |
30
|
|
|
|
|
|
|
'all' => [@EXPORT, @EXPORT_OK_PUBLIC], |
31
|
|
|
|
|
|
|
'internal' => [qw(_set0)], |
32
|
18
|
|
|
18
|
|
2374
|
}; |
|
18
|
|
|
|
|
57
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
my $_first_only = {}; |
35
|
4
|
|
|
4
|
1
|
107
|
sub FIRST_ONLY { $_first_only } |
36
|
|
|
|
|
|
|
|
37
|
18
|
|
|
18
|
|
2243
|
use constant _LOCAL => 'local'; |
|
18
|
|
|
|
|
53
|
|
|
18
|
|
|
|
|
1399
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
# What we use |
40
|
18
|
|
|
18
|
|
128
|
use Config; |
|
18
|
|
|
|
|
38
|
|
|
18
|
|
|
|
|
996
|
|
41
|
18
|
|
|
18
|
|
2206
|
use Data::Hopen qw(getparameters); |
|
18
|
|
|
|
|
44
|
|
|
18
|
|
|
|
|
1195
|
|
42
|
18
|
|
|
18
|
|
9019
|
use Data::Hopen::Util::Data qw(clone forward_opts); |
|
18
|
|
|
|
|
51
|
|
|
18
|
|
|
|
|
1502
|
|
43
|
18
|
|
|
18
|
|
9259
|
use Hash::Merge; |
|
18
|
|
|
|
|
56855
|
|
|
18
|
|
|
|
|
854
|
|
44
|
18
|
|
|
18
|
|
9866
|
use POSIX (); |
|
18
|
|
|
|
|
118661
|
|
|
18
|
|
|
|
|
571
|
|
45
|
18
|
|
|
18
|
|
8339
|
use Set::Scalar; |
|
18
|
|
|
|
|
189756
|
|
|
18
|
|
|
|
|
1264
|
|
46
|
18
|
|
|
18
|
|
8975
|
use Sub::ScopeFinalizer qw(scope_finalizer); |
|
18
|
|
|
|
|
8833
|
|
|
18
|
|
|
|
|
26007
|
|
47
|
|
|
|
|
|
|
|
48
|
|
|
|
|
|
|
# Docs {{{1 |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head1 NAME |
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
Data::Hopen::Scope - a nested key-value store. |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=head1 SYNOPSIS |
55
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
A Scope represents a set of data available to operations. It is a |
57
|
|
|
|
|
|
|
key-value store that falls back to an outer C if a requested key |
58
|
|
|
|
|
|
|
isn't found. |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
This class is the abstract base of Scopes. See L |
61
|
|
|
|
|
|
|
for an example of a concrete implementation using a hash under the |
62
|
|
|
|
|
|
|
hood. Different subclasses use different representations. |
63
|
|
|
|
|
|
|
See L"FUNCTIONS TO BE OVERRIDDEN IN SUBCLASSES"> for more on that topic. |
64
|
|
|
|
|
|
|
|
65
|
|
|
|
|
|
|
=head1 STATIC EXPORTS |
66
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
=head2 FIRST_ONLY |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
A flag used as a L$set> (q.v.). |
70
|
|
|
|
|
|
|
|
71
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
72
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
=head2 outer |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
The fallback C for looking up names not found in this C. |
76
|
|
|
|
|
|
|
If non is provided, it is C, and no fallback will happen. |
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
=head2 local |
79
|
|
|
|
|
|
|
|
80
|
|
|
|
|
|
|
(Default falsy.) If truthy, do not go past this scope when doing local |
81
|
|
|
|
|
|
|
lookups (see L$levels> below). |
82
|
|
|
|
|
|
|
|
83
|
|
|
|
|
|
|
=head2 name |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
Not used, but provided so you can use L to make Scopes. |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
=head2 merge_strategy |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
How the inputs of L will be treated. Case-insensitive. Note that |
90
|
|
|
|
|
|
|
changes after the first time you call L will be ignored! |
91
|
|
|
|
|
|
|
(TODO change this - just need a custom setter) |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
Values are: |
94
|
|
|
|
|
|
|
|
95
|
|
|
|
|
|
|
=over |
96
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
=item C or C<'combine'> (default) |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
L. Same-name keys |
100
|
|
|
|
|
|
|
are merged, so no data is lost. |
101
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
=item C<'keep'> |
103
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
L. Existing data will not be replaced by |
105
|
|
|
|
|
|
|
new data. |
106
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
=item C<'replace'> |
108
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
L. New data will replace existing data. |
110
|
|
|
|
|
|
|
under a particular key will win. |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
=back |
113
|
|
|
|
|
|
|
|
114
|
|
|
|
|
|
|
=head1 PARAMETERS |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
The methods generally receive the same parameters. They are as follows. |
117
|
|
|
|
|
|
|
|
118
|
|
|
|
|
|
|
=head2 $name |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
The name of an item to be looked up. Names must be truthy. That means, |
121
|
|
|
|
|
|
|
among other things, that C<'0'> is not a valid name. |
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
=head2 $set |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
A Scope can have multiple sets of data. C<$set> specifies which one to |
126
|
|
|
|
|
|
|
look in. |
127
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
=over |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
=item * |
131
|
|
|
|
|
|
|
|
132
|
|
|
|
|
|
|
If specified as a number or a name, look only in that set. |
133
|
|
|
|
|
|
|
|
134
|
|
|
|
|
|
|
=item * |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
If C<'*'>, look in every available set at this level, and return a |
137
|
|
|
|
|
|
|
hashref of C<< { set_name => value } >>. |
138
|
|
|
|
|
|
|
Note that this is not recursive --- it won't collect all instances |
139
|
|
|
|
|
|
|
of the given name from all sets in all the levels. (TODO? change this?) |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=item * |
142
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
If L, look in only the first set (usually named C<0>). |
144
|
|
|
|
|
|
|
|
145
|
|
|
|
|
|
|
=item * |
146
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
If unspecified or undefined, look in every available set at this level, and |
148
|
|
|
|
|
|
|
return the first one found, regardless of which set it comes from. |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
=back |
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
=head2 $levels |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
How many levels up (L) to go when performing an operation. Note: |
155
|
|
|
|
|
|
|
chains more than C (L) Scopes long may fail in |
156
|
|
|
|
|
|
|
unexpected ways, depending on your platform! For 32- or 64-bit platforms, |
157
|
|
|
|
|
|
|
that number is at least 2,000,000,000, so you're probably OK :) . |
158
|
|
|
|
|
|
|
|
159
|
|
|
|
|
|
|
=over |
160
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
=item * |
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
If numeric and non-negative, go up that many more levels |
164
|
|
|
|
|
|
|
(i.e., C<$levels==0> means only return this scope's local names). |
165
|
|
|
|
|
|
|
|
166
|
|
|
|
|
|
|
=item * |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
If C<'local'>, go up until reaching a scope with L set. |
169
|
|
|
|
|
|
|
If the current scope has L set, don't go up at all. |
170
|
|
|
|
|
|
|
|
171
|
|
|
|
|
|
|
=item * |
172
|
|
|
|
|
|
|
|
173
|
|
|
|
|
|
|
If not provided or not defined, go all the way to the outermost Scope. |
174
|
|
|
|
|
|
|
|
175
|
|
|
|
|
|
|
=back |
176
|
|
|
|
|
|
|
|
177
|
|
|
|
|
|
|
=head1 METHODS |
178
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
See also L, below, which is part of the public API. |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
=cut |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# }}}1 |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# Handle $levels and invoke a function on the outer scope if appropriate. |
186
|
|
|
|
|
|
|
# Usage: |
187
|
|
|
|
|
|
|
# $self->_invoke('method_name', $levels, [other args to be passed, starting |
188
|
|
|
|
|
|
|
# with invocant, if any] |
189
|
|
|
|
|
|
|
# A new levels value will be added to the end of the args as -levels=>$val. |
190
|
|
|
|
|
|
|
# Returns undef if there's no more traversing to be done. |
191
|
|
|
|
|
|
|
|
192
|
|
|
|
|
|
|
sub _invoke { |
193
|
731
|
50
|
|
731
|
|
1783
|
my $self = shift or croak 'Need an instance'; |
194
|
731
|
50
|
|
|
|
1567
|
my $method_name = shift or croak 'Need a method name'; |
195
|
731
|
|
|
|
|
1038
|
my $levels = shift; |
196
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
# Handle 'local'-scoped searches by terminating when $self->local is set. |
198
|
731
|
100
|
100
|
|
|
4656
|
$levels = 0 if ( ($levels//'') eq _LOCAL) && $self->local; |
|
|
|
100
|
|
|
|
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# Search the outer scopes |
201
|
731
|
100
|
100
|
|
|
13977
|
if($self->outer && # Search the outer scopes |
|
|
|
100
|
|
|
|
|
202
|
|
|
|
|
|
|
(!defined($levels) || ($levels eq _LOCAL) || ($levels>0) ) |
203
|
|
|
|
|
|
|
) { |
204
|
544
|
100
|
|
|
|
5012
|
my $newlevels = |
|
|
100
|
|
|
|
|
|
205
|
|
|
|
|
|
|
!defined($levels) ? undef : |
206
|
|
|
|
|
|
|
( ($levels eq _LOCAL) ? _LOCAL : ($levels-1) ); |
207
|
|
|
|
|
|
|
|
208
|
544
|
|
|
|
|
8585
|
unshift @_, $self->outer; |
209
|
544
|
|
|
|
|
3010
|
push @_, -levels => $newlevels; |
210
|
544
|
|
|
|
|
8256
|
my $coderef = $self->outer->can($method_name); |
211
|
544
|
50
|
|
|
|
4109
|
return $coderef->(@_) if $coderef; |
212
|
|
|
|
|
|
|
} |
213
|
187
|
|
|
|
|
1695
|
return undef; |
214
|
|
|
|
|
|
|
} #_invoke() |
215
|
|
|
|
|
|
|
|
216
|
|
|
|
|
|
|
=head2 find |
217
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
Find a named data item in the scope and return it. Looks up the scope chain |
219
|
|
|
|
|
|
|
to the outermost scope if necessary. Returns undef on |
220
|
|
|
|
|
|
|
failure. Usage: |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
$scope->find($name[, $set[, $levels]]); |
223
|
|
|
|
|
|
|
$scope->find($name[, -set => $set][, -levels => $levels]); |
224
|
|
|
|
|
|
|
# Alternative using named arguments |
225
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
Dies if given a falsy name, notably, C<'0'>. |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
=cut |
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub find { |
231
|
544
|
|
|
544
|
1
|
8431
|
my ($self, %args) = getparameters('self', [qw(name ; set levels)], @_); |
232
|
544
|
50
|
|
|
|
40751
|
croak 'Need a name' unless $args{name}; |
233
|
|
|
|
|
|
|
# Therefore, '0' is not a valid name |
234
|
544
|
|
|
|
|
949
|
my $levels = $args{levels}; |
235
|
|
|
|
|
|
|
|
236
|
544
|
|
|
|
|
1937
|
my $here = $self->_find_here($args{name}, $args{set}); |
237
|
544
|
100
|
|
|
|
4414
|
return $here if defined $here; |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
return $self->_invoke('find', $args{levels}, |
240
|
207
|
|
|
|
|
830
|
forward_opts(\%args, {'-'=>1}, qw(name set)) |
241
|
|
|
|
|
|
|
); |
242
|
|
|
|
|
|
|
} #find() |
243
|
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
=head2 names |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
Returns a L of the names of the items available through this |
247
|
|
|
|
|
|
|
Scope, optionally including all its parent Scopes (if any). Usage |
248
|
|
|
|
|
|
|
and example: |
249
|
|
|
|
|
|
|
|
250
|
|
|
|
|
|
|
my $set = $scope->names([$levels]); |
251
|
|
|
|
|
|
|
say "Name $_ is available" foreach @$set; # Set::Scalar supports @$set |
252
|
|
|
|
|
|
|
|
253
|
|
|
|
|
|
|
If no names are available in the given C<$levels>, returns an empty |
254
|
|
|
|
|
|
|
C. |
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
TODO support a C<$set> parameter |
257
|
|
|
|
|
|
|
|
258
|
|
|
|
|
|
|
=cut |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
sub names { |
261
|
74
|
|
|
74
|
1
|
12059
|
my ($self, %args) = getparameters('self', [qw(; levels)], @_); |
262
|
74
|
|
|
|
|
4383
|
my $retval = Set::Scalar->new; |
263
|
74
|
|
|
|
|
6297
|
$self->_fill_names($retval, $args{levels}); |
264
|
74
|
|
|
|
|
393
|
return $retval; |
265
|
|
|
|
|
|
|
} #names() |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
# Implementation of names() |
268
|
|
|
|
|
|
|
sub _fill_names { |
269
|
|
|
|
|
|
|
#say Dumper(\@_); |
270
|
191
|
|
|
191
|
|
778
|
my ($self, %args) = getparameters('self', [qw(retval levels)], @_); |
271
|
|
|
|
|
|
|
|
272
|
191
|
|
|
|
|
20854
|
$self->_names_here($args{retval}); # Insert this scope's names |
273
|
|
|
|
|
|
|
|
274
|
191
|
|
|
|
|
11047
|
return $self->_invoke('_fill_names', $args{levels}, -retval=>$args{retval}); |
275
|
|
|
|
|
|
|
} #_fill_names() |
276
|
|
|
|
|
|
|
|
277
|
|
|
|
|
|
|
=head2 as_hashref |
278
|
|
|
|
|
|
|
|
279
|
|
|
|
|
|
|
Returns a hash of the items available through this Scope, optionally |
280
|
|
|
|
|
|
|
including all its parent Scopes (if any). Usage: |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
my $hashref = $scope->as_hashref([-levels => $levels][, -deep => $deep]) |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
If C<$levels> is provided and nonzero, go up that many more levels |
285
|
|
|
|
|
|
|
(i.e., C<$levels==0> means only return this scope's local names). |
286
|
|
|
|
|
|
|
If C<$levels> is not provided, go all the way to the outermost Scope. |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
If C<$deep> is provided and truthy, make a deep copy of each value (using |
289
|
|
|
|
|
|
|
L. Otherwise, just copy. |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
TODO support a C<$set> parameter |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=cut |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
sub as_hashref { |
296
|
107
|
|
|
107
|
1
|
1472
|
my ($self, %args) = getparameters('self', [qw(; levels deep)], @_); |
297
|
107
|
|
|
|
|
4540
|
my $hrRetval = {}; |
298
|
107
|
|
|
|
|
506
|
$self->_fill_hashref($hrRetval, $args{deep}, $args{levels}); |
299
|
107
|
|
|
|
|
13289
|
return $hrRetval; |
300
|
|
|
|
|
|
|
} #as_hashref() |
301
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
# Implementation of as_hashref. Mutates the provided $hrRetval. |
303
|
|
|
|
|
|
|
sub _fill_hashref { |
304
|
333
|
|
|
333
|
|
1309
|
my ($self, %args) = getparameters('self', [qw(retval levels deep)], @_); |
305
|
333
|
|
|
|
|
30229
|
my $hrRetval = $args{retval}; |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
# Innermost wins, so copy ours first. |
308
|
333
|
|
|
|
|
1210
|
my $names = Set::Scalar->new; |
309
|
333
|
|
|
|
|
20806
|
$self->_names_here($names); |
310
|
|
|
|
|
|
|
|
311
|
333
|
|
|
|
|
19888
|
foreach my $k (@$names) { |
312
|
281
|
100
|
|
|
|
1894
|
unless(exists($hrRetval->{$k})) { # An inner scope might have set it |
313
|
199
|
|
|
|
|
538
|
my $val = $self->find($k, -levels => 0); |
314
|
|
|
|
|
|
|
$hrRetval->{$k} = |
315
|
199
|
100
|
|
|
|
699
|
($args{deep} ? clone($val) : $val); |
316
|
|
|
|
|
|
|
} |
317
|
|
|
|
|
|
|
} |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
return $self->_invoke('_fill_hashref', $args{levels}, |
320
|
333
|
|
|
|
|
2873
|
forward_opts(\%args, {'-'=>1}, qw(retval deep))); |
321
|
|
|
|
|
|
|
} #_fill_hashref() |
322
|
|
|
|
|
|
|
|
323
|
|
|
|
|
|
|
=head2 outerize |
324
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
Set L, and return a scalar that will restore L when it |
326
|
|
|
|
|
|
|
goes out of scope. Usage: |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
my $saver = $scope->outerize($new_outer); |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
C<$new_outer> may be C or a valid C. |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=cut |
333
|
|
|
|
|
|
|
|
334
|
|
|
|
|
|
|
sub outerize { |
335
|
113
|
|
|
113
|
1
|
2275
|
my ($self, %args) = getparameters('self', [qw(outer)], @_); |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
croak 'Need a Scope' unless |
338
|
|
|
|
|
|
|
(!defined($args{outer})) or |
339
|
113
|
50
|
33
|
|
|
6163
|
(ref $args{outer} && eval { $args{outer}->DOES('Data::Hopen::Scope') }); |
|
103
|
|
66
|
|
|
863
|
|
340
|
|
|
|
|
|
|
|
341
|
|
|
|
|
|
|
# Protect the author of this function from himself |
342
|
113
|
50
|
|
|
|
324
|
croak 'Sorry, but I must insist that you save my return value' |
343
|
|
|
|
|
|
|
unless defined wantarray; |
344
|
|
|
|
|
|
|
|
345
|
113
|
|
|
|
|
2288
|
my $old_outer = $self->outer; |
346
|
113
|
|
|
113
|
|
1198
|
my $saver = scope_finalizer { $self->outer($old_outer) }; |
|
113
|
|
|
|
|
4217
|
|
347
|
113
|
|
|
|
|
3946
|
$self->outer($args{outer}); |
348
|
113
|
|
|
|
|
647
|
return $saver; |
349
|
|
|
|
|
|
|
} #outerize() |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
=head2 _merger (internal) |
352
|
|
|
|
|
|
|
|
353
|
|
|
|
|
|
|
Creates a L instance based on L, if one |
354
|
|
|
|
|
|
|
doesn't exist. Returns the instance. |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
Provided for the convenience of subclasses; not actually used by |
357
|
|
|
|
|
|
|
any concrete functions in this package. |
358
|
|
|
|
|
|
|
|
359
|
|
|
|
|
|
|
=cut |
360
|
|
|
|
|
|
|
|
361
|
|
|
|
|
|
|
sub _merger { |
362
|
40
|
50
|
|
40
|
|
102
|
my $self = shift or croak 'Need an instance'; |
363
|
40
|
100
|
|
|
|
999
|
return $self->_merger_instance if $self->_merger_instance; |
364
|
|
|
|
|
|
|
|
365
|
29
|
|
|
|
|
671
|
my $s = $self->merge_strategy; |
366
|
29
|
50
|
|
|
|
293
|
my $precedence = |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
367
|
|
|
|
|
|
|
!defined $s ? 'RETAINMENT_PRECEDENT' : |
368
|
|
|
|
|
|
|
$s =~ /^combine$/i ? 'RETAINMENT_PRECEDENT' : |
369
|
|
|
|
|
|
|
$s =~ /^keep$/i ? 'LEFT_PRECEDENT' : |
370
|
|
|
|
|
|
|
$s =~ /^replace$/i ? 'RIGHT_PRECEDENT' : |
371
|
|
|
|
|
|
|
undef; |
372
|
29
|
50
|
|
|
|
87
|
die "Invalid merge strategy $s" unless defined $precedence; |
373
|
|
|
|
|
|
|
|
374
|
29
|
|
|
|
|
174
|
my $merger = Hash::Merge->new($precedence); |
375
|
29
|
|
|
|
|
3051
|
$merger->set_clone_behavior(false); |
376
|
|
|
|
|
|
|
# TODO CHECKME --- I would rather clone everything except blessed |
377
|
|
|
|
|
|
|
# references, but doing so appears to be nontrivial. For now, |
378
|
|
|
|
|
|
|
# I am trying not cloning. |
379
|
29
|
|
|
|
|
986
|
$self->_merger_instance($merger); |
380
|
|
|
|
|
|
|
|
381
|
29
|
|
|
|
|
212
|
return $merger; |
382
|
|
|
|
|
|
|
} #_merger() |
383
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
=head1 FUNCTIONS TO BE OVERRIDDEN IN SUBCLASSES |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
To implement a Scope with a different data-storage model than the hash |
387
|
|
|
|
|
|
|
this class uses, subclass Scope and override these functions. Of these, |
388
|
|
|
|
|
|
|
only L and L are part of the public API. |
389
|
|
|
|
|
|
|
|
390
|
|
|
|
|
|
|
=head2 put |
391
|
|
|
|
|
|
|
|
392
|
|
|
|
|
|
|
Add key-value pairs to this scope. Returns the scope so you can |
393
|
|
|
|
|
|
|
chain. Example usage: |
394
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
my $scope = Data::Hopen::Scope->new()->put(foo => 1); |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
C overwrites data in case of any conflicts. See L if you |
398
|
|
|
|
|
|
|
want more control. |
399
|
|
|
|
|
|
|
|
400
|
|
|
|
|
|
|
C may be called with no parameters, in which case it is a no-op. |
401
|
|
|
|
|
|
|
This is so you can say C<< $s->put(%foo) >> without first having to |
402
|
|
|
|
|
|
|
check whether C<%foo> is nonempty. |
403
|
|
|
|
|
|
|
|
404
|
|
|
|
|
|
|
TODO add C<$set> option. TODO? add -deep option? |
405
|
|
|
|
|
|
|
|
406
|
|
|
|
|
|
|
=cut |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
sub put { |
409
|
|
|
|
|
|
|
... |
410
|
1
|
|
|
1
|
1
|
1656
|
} #put() |
411
|
|
|
|
|
|
|
|
412
|
|
|
|
|
|
|
=head2 merge |
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
Merges key-value pairs into this scope. Returns the scope so you can |
415
|
|
|
|
|
|
|
chain. Example usage: |
416
|
|
|
|
|
|
|
|
417
|
|
|
|
|
|
|
my $scope = Data::Hopen::Scope->new()->merge(foo => 1); |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
See L for options controlling the behaviour of C. |
420
|
|
|
|
|
|
|
=cut |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
sub merge { #blub blub |
423
|
1
|
50
|
|
1
|
1
|
669
|
my $self = shift or croak 'Need an instance'; |
424
|
1
|
|
|
|
|
5
|
my $merger = $self->_merger; |
425
|
|
|
|
|
|
|
... |
426
|
1
|
|
|
|
|
14
|
} #merge() |
427
|
|
|
|
|
|
|
|
428
|
|
|
|
|
|
|
=head2 _names_here |
429
|
|
|
|
|
|
|
|
430
|
|
|
|
|
|
|
Populates a L with the names of the items stored in this Scope, |
431
|
|
|
|
|
|
|
but B any outer Scope. Called as: |
432
|
|
|
|
|
|
|
|
433
|
|
|
|
|
|
|
$scope->_names_here($retval[, $set]) |
434
|
|
|
|
|
|
|
|
435
|
|
|
|
|
|
|
C<$retval> is the C instance. C<$set> is as |
436
|
|
|
|
|
|
|
defined L. |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
No return value. |
439
|
|
|
|
|
|
|
|
440
|
|
|
|
|
|
|
=cut |
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
sub _names_here { |
443
|
|
|
|
|
|
|
... |
444
|
1
|
|
|
1
|
|
669
|
} #_names_here() |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
=head2 _find_here |
447
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
Looks for a given item in this scope, but B any outer scope. Called as: |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
$scope->_find_here($name[, $set]) |
451
|
|
|
|
|
|
|
|
452
|
|
|
|
|
|
|
Returns the value, or C if not found. |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=cut |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
sub _find_here { |
457
|
|
|
|
|
|
|
... |
458
|
1
|
|
|
1
|
|
659
|
} #_find_here() |
459
|
|
|
|
|
|
|
|
460
|
|
|
|
|
|
|
=head1 HELPER FUNCTIONS |
461
|
|
|
|
|
|
|
|
462
|
|
|
|
|
|
|
=head2 is_first_only |
463
|
|
|
|
|
|
|
|
464
|
|
|
|
|
|
|
Test whether the given scalar is L. Usage: C. |
465
|
|
|
|
|
|
|
|
466
|
|
|
|
|
|
|
=cut |
467
|
|
|
|
|
|
|
|
468
|
|
|
|
|
|
|
sub is_first_only { |
469
|
1078
|
100
|
100
|
1078
|
1
|
3553
|
ref $_[0] && |
470
|
|
|
|
|
|
|
ref $_[0] eq ref $_first_only && |
471
|
|
|
|
|
|
|
refaddr $_[0] == refaddr $_first_only |
472
|
|
|
|
|
|
|
} #is_first_only() |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
=head2 _set0 |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
For use only by subclasses. |
477
|
|
|
|
|
|
|
|
478
|
|
|
|
|
|
|
Don't support C<-set>, but permit C<< -set=>0 >> and C<< -set=>FIRST_ONLY >> |
479
|
|
|
|
|
|
|
for the sake of code calling through the Scope interface. Call as |
480
|
|
|
|
|
|
|
C>. Returns truthy if OK, falsy if not. May modify its argument. |
481
|
|
|
|
|
|
|
Better a readily-obvious crash than a subtle bug! |
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
=cut |
484
|
|
|
|
|
|
|
|
485
|
|
|
|
|
|
|
sub _set0 { |
486
|
1073
|
|
100
|
1073
|
|
5701
|
$_[0] //= 0; # Give the caller a default set |
487
|
1073
|
100
|
|
|
|
2126
|
$_[0] = 0 if Data::Hopen::Scope::is_first_only($_[0]); |
488
|
1073
|
|
|
|
|
2034
|
my $set = shift; |
489
|
1073
|
100
|
100
|
|
|
2585
|
return false if $set ne '0' && $set ne '*'; |
490
|
1071
|
|
|
|
|
3098
|
return true; |
491
|
|
|
|
|
|
|
} #_set0() |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
1; |
494
|
|
|
|
|
|
|
__END__ |