line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
5
|
|
|
5
|
|
257702
|
use v5.14; |
|
5
|
|
|
|
|
18
|
|
2
|
5
|
|
|
5
|
|
28
|
use warnings; |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
220
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Datify v0.20.064; |
5
|
|
|
|
|
|
|
# ABSTRACT: Simple stringification of data. |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
|
8
|
5
|
|
|
5
|
|
31
|
use mro (); #qw( get_linear_isa ); |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
73
|
|
9
|
5
|
|
|
5
|
|
22
|
use overload (); #qw( Method Overloaded ); |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
69
|
|
10
|
|
|
|
|
|
|
|
11
|
5
|
|
|
5
|
|
23
|
use Carp (); #qw( carp croak ); |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
97
|
|
12
|
5
|
|
|
5
|
|
26
|
use List::Util (); #qw( reduce sum ); |
|
5
|
|
|
|
|
7
|
|
|
5
|
|
|
|
|
133
|
|
13
|
5
|
|
|
5
|
|
2438
|
use LooksLike v0.20.060 (); #qw( number numeric representation ); |
|
5
|
|
|
|
|
18468
|
|
|
5
|
|
|
|
|
177
|
|
14
|
5
|
|
|
5
|
|
38
|
use Scalar::Util (); #qw( blessed refaddr reftype ); |
|
5
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
103
|
|
15
|
5
|
|
|
5
|
|
2495
|
use String::Tools v0.19.045 (); #qw( stitch stringify subst ); |
|
5
|
|
|
|
|
7273
|
|
|
5
|
|
|
|
|
145
|
|
16
|
5
|
|
|
5
|
|
2341
|
use Sub::Util 1.40 (); #qw( subname ); |
|
5
|
|
|
|
|
1583
|
|
|
5
|
|
|
|
|
3601
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
### Constructor ### |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub new { |
23
|
2905
|
|
50
|
2905
|
1
|
15004
|
my $class = shift || __PACKAGE__; |
24
|
|
|
|
|
|
|
|
25
|
2905
|
|
|
|
|
3399
|
my %self = (); |
26
|
2905
|
50
|
|
|
|
4727
|
if ( defined( my $blessed = Scalar::Util::blessed($class) ) ) { |
27
|
0
|
|
|
|
|
0
|
%self = %$class; # shallow copy |
28
|
0
|
|
|
|
|
0
|
$class = $blessed; |
29
|
|
|
|
|
|
|
} |
30
|
2905
|
100
|
|
|
|
5892
|
return @_ ? bless( \%self, $class )->set(@_) : bless( \%self, $class ); |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
### Accessor ### |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub exists { |
41
|
7375
|
|
|
7375
|
1
|
7934
|
my $self = shift; |
42
|
7375
|
50
|
|
|
|
10540
|
return unless my $count = scalar(@_); |
43
|
|
|
|
|
|
|
|
44
|
7375
|
|
|
|
|
9599
|
my $SETTINGS = $self->_settings; |
45
|
7375
|
100
|
|
|
|
14082
|
if ( Scalar::Util::blessed($self) ) { |
46
|
|
|
|
|
|
|
return $count == 1 |
47
|
|
|
|
|
|
|
? exists $self->{ $_[0] } && $self |
48
|
|
|
|
|
|
|
|| exists $SETTINGS->{ $_[0] } && $SETTINGS |
49
|
|
|
|
|
|
|
: map { |
50
|
7331
|
50
|
100
|
|
|
30626
|
exists $self->{ $_ } && $self |
51
|
0
|
0
|
0
|
|
|
0
|
|| exists $SETTINGS->{ $_ } && $SETTINGS |
|
|
|
0
|
|
|
|
|
52
|
|
|
|
|
|
|
} @_; |
53
|
|
|
|
|
|
|
} else { |
54
|
|
|
|
|
|
|
return |
55
|
|
|
|
|
|
|
$count == 1 ? exists $SETTINGS->{ $_[0] } && $SETTINGS |
56
|
44
|
0
|
66
|
|
|
522
|
: map { exists $SETTINGS->{ $_ } && $SETTINGS } @_; |
|
0
|
50
|
|
|
|
0
|
|
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub _get_setting { |
63
|
7337
|
|
|
7337
|
|
11493
|
my $setting = $_[0]->exists( local $_ = $_[1] ); |
64
|
7337
|
100
|
|
|
|
19303
|
return $setting ? $setting->{$_} : do { |
65
|
689
|
50
|
|
|
|
975
|
Carp::carp( 'Unknown key ', $_ ) |
66
|
|
|
|
|
|
|
unless $_[0]->_internal(1); |
67
|
|
|
|
|
|
|
undef |
68
|
689
|
|
|
|
|
1429
|
}; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
sub get { |
71
|
6469
|
|
|
6469
|
1
|
11625
|
my $self = shift; |
72
|
6469
|
|
|
|
|
6787
|
my $count = scalar(@_); |
73
|
|
|
|
|
|
|
|
74
|
6469
|
100
|
|
|
|
13737
|
if ( defined( my $class = Scalar::Util::blessed($self) ) ) { |
75
|
|
|
|
|
|
|
return |
76
|
0
|
|
|
|
|
0
|
$count == 0 ? ( %{ $self->_settings }, %$self ) |
77
|
|
|
|
|
|
|
: $count == 1 ? $self->_get_setting(shift) |
78
|
6462
|
100
|
|
|
|
12863
|
: map { $self->_get_setting($_) } @_; |
|
1316
|
50
|
|
|
|
1856
|
|
79
|
|
|
|
|
|
|
} else { |
80
|
|
|
|
|
|
|
return |
81
|
1
|
|
|
|
|
4
|
$count == 0 ? %{ $self->_settings } |
82
|
|
|
|
|
|
|
: $count == 1 ? $self->_get_setting(shift) |
83
|
7
|
50
|
|
|
|
27
|
: map { $self->_get_setting($_) } @_; |
|
0
|
100
|
|
|
|
0
|
|
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
### Setter ### |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub set { |
92
|
1238
|
|
|
1238
|
1
|
9865
|
my $self = shift; |
93
|
1238
|
50
|
|
|
|
2022
|
return $self unless @_; |
94
|
1238
|
|
|
|
|
2612
|
my %set = @_; |
95
|
|
|
|
|
|
|
|
96
|
1238
|
|
|
|
|
1534
|
my $return; |
97
|
|
|
|
|
|
|
my $class; |
98
|
1238
|
100
|
|
|
|
2812
|
if ( defined( $class = Scalar::Util::blessed($self) ) ) { |
99
|
|
|
|
|
|
|
# Make a shallow copy |
100
|
1111
|
|
|
|
|
3809
|
$self = bless { %$self }, $class; |
101
|
1111
|
|
|
|
|
1595
|
$return = 0; |
102
|
|
|
|
|
|
|
} else { |
103
|
127
|
|
|
|
|
164
|
$class = $self; |
104
|
127
|
|
|
|
|
217
|
$self = $class->_settings; |
105
|
127
|
|
|
|
|
180
|
$return = 1; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
1238
|
100
|
|
|
|
2400
|
delete $self->{keyword_set} if ( $set{keywords} ); |
109
|
1238
|
|
|
|
|
1698
|
delete $self->{"_tr$_"} for grep { exists $set{"quote$_"} } ( 1, 2, 3 ); |
|
3714
|
|
|
|
|
6843
|
|
110
|
|
|
|
|
|
|
|
111
|
1238
|
|
|
|
|
2023
|
my $internal = $class->_internal; |
112
|
1238
|
|
|
|
|
3212
|
while ( my ( $k, $v ) = each %set ) { |
113
|
1441
|
100
|
100
|
|
|
2540
|
Carp::carp( 'Unknown key ', $k ) |
114
|
|
|
|
|
|
|
unless $internal || $class->exists($k); |
115
|
1441
|
100
|
100
|
|
|
3941
|
study($v) if defined($v) && !ref($v); |
116
|
1441
|
|
|
|
|
3977
|
$self->{$k} = $v; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
1238
|
|
|
|
|
2824
|
return ( $self, $class )[$return]; |
120
|
|
|
|
|
|
|
} |
121
|
|
|
|
|
|
|
|
122
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
sub add_handler { |
126
|
0
|
|
|
0
|
1
|
0
|
my $self = &self; |
127
|
0
|
|
|
|
|
0
|
my $code = pop; |
128
|
0
|
0
|
|
|
|
0
|
my $pkg = length( $_[0] ) ? shift : caller; |
129
|
|
|
|
|
|
|
|
130
|
0
|
0
|
|
|
|
0
|
if ( my $name = _nameify($pkg) ) { |
131
|
5
|
|
|
5
|
|
41
|
no strict 'refs'; |
|
5
|
|
|
|
|
28
|
|
|
5
|
|
|
|
|
6134
|
|
132
|
0
|
|
|
|
|
0
|
*{$name} = $code; |
|
0
|
|
|
|
|
0
|
|
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
} |
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
__PACKAGE__->set( |
140
|
|
|
|
|
|
|
# Var options |
141
|
|
|
|
|
|
|
name => '$self', |
142
|
|
|
|
|
|
|
assign => '$var = $value;', |
143
|
|
|
|
|
|
|
list => '($_)', |
144
|
|
|
|
|
|
|
list_sep => ', ', |
145
|
|
|
|
|
|
|
beautify => undef, |
146
|
|
|
|
|
|
|
); |
147
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
# Name can be any of the following: |
149
|
|
|
|
|
|
|
# * package name (optional) followed by: |
150
|
|
|
|
|
|
|
# * normal word |
151
|
|
|
|
|
|
|
# * :: |
152
|
|
|
|
|
|
|
# * Perl special variable: |
153
|
|
|
|
|
|
|
# * numbers |
154
|
|
|
|
|
|
|
# * punctuation |
155
|
|
|
|
|
|
|
# * control character |
156
|
|
|
|
|
|
|
# * control word |
157
|
|
|
|
|
|
|
my $sigils = '[\\x24\\x25\\x40]'; # $%@ |
158
|
|
|
|
|
|
|
my $package = '[[:alpha:]]\w*(?:\::\w+)*'; |
159
|
|
|
|
|
|
|
my $word = '[[:alpha:]_]\w*'; |
160
|
|
|
|
|
|
|
my $digits = '\d+'; |
161
|
|
|
|
|
|
|
my $punct = '[[:punct:]]'; |
162
|
|
|
|
|
|
|
my $cntrl = '(?:[[:cntrl:]]|\^[[:upper:]])'; |
163
|
|
|
|
|
|
|
my $cntrl_word = "$cntrl$word"; |
164
|
|
|
|
|
|
|
my $varname |
165
|
|
|
|
|
|
|
= '(?:' . join( '|', $word, $digits, $punct, $cntrl, $cntrl_word ) . ')'; |
166
|
|
|
|
|
|
|
$varname .= "|\\{\\s*$varname\\s*\\}"; |
167
|
|
|
|
|
|
|
$varname = "(?:$varname)"; |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
sub varify { |
171
|
41
|
|
|
41
|
1
|
21860
|
my $self = &self; |
172
|
41
|
|
|
|
|
71
|
my ($sigil, $name); |
173
|
41
|
50
|
33
|
|
|
157
|
if ( defined $_[0] && !ref $_[0] ) { |
174
|
41
|
|
|
|
|
781
|
( $sigil, $name ) |
175
|
|
|
|
|
|
|
= $_[0] =~ /^($sigils)?((?:$package\::)?$varname|$package\::)$/; |
176
|
41
|
50
|
|
|
|
130
|
shift if length $name; |
177
|
|
|
|
|
|
|
} |
178
|
41
|
50
|
|
|
|
87
|
my $value = 1 == @_ ? shift : \@_; |
179
|
|
|
|
|
|
|
|
180
|
41
|
50
|
|
|
|
71
|
if ( length $name ) { |
181
|
41
|
50
|
|
|
|
117
|
if ( $name =~ /[[:cntrl:]]/ ) { |
182
|
0
|
|
|
|
|
0
|
$name =~ s/([[:cntrl:]])/'^' . chr(64 + ord($1) % 64)/e; |
|
0
|
|
|
|
|
0
|
|
183
|
0
|
|
|
|
|
0
|
$name =~ s/($cntrl_word)(?!\s*\})/\{$1\}/; |
184
|
|
|
|
|
|
|
} |
185
|
|
|
|
|
|
|
} else { |
186
|
0
|
0
|
|
|
|
0
|
if ( defined( my $ref = Scalar::Util::blessed($value) ) ) { |
187
|
0
|
|
|
|
|
0
|
$name = _nameify($ref); |
188
|
|
|
|
|
|
|
} else { |
189
|
0
|
|
|
|
|
0
|
$name = $self->get('name'); |
190
|
|
|
|
|
|
|
} |
191
|
|
|
|
|
|
|
} |
192
|
41
|
50
|
|
|
|
77
|
Carp::croak "Missing name" unless ( length $name ); |
193
|
|
|
|
|
|
|
|
194
|
41
|
100
|
|
|
|
69
|
unless ($sigil) { |
195
|
22
|
|
|
|
|
72
|
my $ref = ref $value; |
196
|
22
|
50
|
|
|
|
60
|
$sigil |
|
|
50
|
|
|
|
|
|
197
|
|
|
|
|
|
|
= $ref eq 'ARRAY' ? '@' |
198
|
|
|
|
|
|
|
: $ref eq 'HASH' ? '%' |
199
|
|
|
|
|
|
|
: '$'; |
200
|
|
|
|
|
|
|
} |
201
|
41
|
|
|
|
|
69
|
$name = $sigil . $name; |
202
|
41
|
|
|
|
|
99
|
$self = $self->set( name => $name ); |
203
|
|
|
|
|
|
|
|
204
|
41
|
0
|
|
|
|
124
|
$value |
|
|
0
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
205
|
|
|
|
|
|
|
= $sigil eq '$' ? $self->scalarify($value) |
206
|
|
|
|
|
|
|
: $sigil eq '@' ? _subst( $self->get('list'), $self->listify($value) ) |
207
|
|
|
|
|
|
|
: $sigil eq '%' ? _subst( $self->get('list'), $self->pairify($value) ) |
208
|
|
|
|
|
|
|
: $self->scalarify($value) |
209
|
|
|
|
|
|
|
; |
210
|
|
|
|
|
|
|
|
211
|
41
|
|
|
|
|
74
|
$value = _subst( $self->get('assign'), var => $name, value => $value ); |
212
|
41
|
50
|
|
|
|
3265
|
if ( my $beautify = $self->get('beautify') ) { |
213
|
0
|
|
|
|
|
0
|
return $beautify->($value); |
214
|
|
|
|
|
|
|
} else { |
215
|
41
|
|
|
|
|
193
|
return $value; |
216
|
|
|
|
|
|
|
} |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
|
220
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
### Scalar: undef ### |
222
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
|
224
|
|
|
|
|
|
|
__PACKAGE__->set( |
225
|
|
|
|
|
|
|
# Undef options |
226
|
|
|
|
|
|
|
null => 'undef', |
227
|
|
|
|
|
|
|
); |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
|
230
|
|
|
|
|
|
|
sub undefify { |
231
|
21
|
|
|
21
|
1
|
40
|
my $self = &self; |
232
|
21
|
50
|
33
|
|
|
70
|
return $self->scalarify(shift) if @_ and defined($_[0]); |
233
|
21
|
|
|
|
|
47
|
return $self->get('null'); |
234
|
|
|
|
|
|
|
} |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
### Scalar: boolean ### |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
__PACKAGE__->set( |
242
|
|
|
|
|
|
|
# Boolean options |
243
|
|
|
|
|
|
|
true => 1, |
244
|
|
|
|
|
|
|
false => "''", |
245
|
|
|
|
|
|
|
); |
246
|
|
|
|
|
|
|
|
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
sub booleanify { |
249
|
0
|
|
|
0
|
1
|
0
|
my $self = &self; |
250
|
0
|
0
|
|
|
|
0
|
local $_ = shift if @_; |
251
|
0
|
0
|
|
|
|
0
|
return $self->undefify unless defined; |
252
|
0
|
0
|
|
|
|
0
|
return $_ ? $self->get('true') : $self->get('false'); |
253
|
|
|
|
|
|
|
} |
254
|
|
|
|
|
|
|
|
255
|
|
|
|
|
|
|
|
256
|
|
|
|
|
|
|
|
257
|
|
|
|
|
|
|
### Scalar: single-quoted string ### |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
sub stringify1 { |
261
|
400
|
|
|
400
|
1
|
4412
|
my $self = &self; |
262
|
400
|
50
|
|
|
|
920
|
local $_ = shift if @_; |
263
|
400
|
50
|
|
|
|
651
|
return $self->undefify unless defined; |
264
|
400
|
50
|
|
|
|
559
|
$_ = String::Tools::stringify($_) if ref; |
265
|
400
|
|
|
|
|
678
|
my $quote1 = $self->get('quote1'); |
266
|
400
|
|
66
|
|
|
1189
|
my ( $open, $close ) = $self->_get_delim( shift // $quote1 ); |
267
|
|
|
|
|
|
|
|
268
|
400
|
|
|
|
|
674
|
$self = $self->set( encode => $self->get('encode1') ); |
269
|
400
|
|
|
|
|
726
|
my $to_encode = $self->_to_encode( $open, $close ); |
270
|
400
|
|
|
|
|
1403
|
s/([$to_encode])/$self->_encode_char($1)/eg; |
|
116
|
|
|
|
|
255
|
|
271
|
|
|
|
|
|
|
|
272
|
400
|
100
|
|
|
|
784
|
if ( $quote1 ne $open ) { |
273
|
1
|
50
|
|
|
|
7
|
if ( $open =~ /\w/ ) { |
274
|
0
|
|
|
|
|
0
|
$open = ' ' . $open; |
275
|
0
|
|
|
|
|
0
|
$close = ' ' . $close; |
276
|
|
|
|
|
|
|
} |
277
|
1
|
|
|
|
|
4
|
$open = $self->get('q1') . $open; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
400
|
|
|
|
|
2794
|
return sprintf '%s%s%s', $open, $_, $close; |
281
|
|
|
|
|
|
|
} |
282
|
|
|
|
|
|
|
|
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
|
285
|
|
|
|
|
|
|
### Scalar: double-quoted string ### |
286
|
|
|
|
|
|
|
|
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
sub stringify2 { |
289
|
60
|
|
|
60
|
1
|
4455
|
my $self = &self; |
290
|
60
|
50
|
|
|
|
167
|
local $_ = shift if @_; |
291
|
60
|
50
|
|
|
|
161
|
return $self->undefify unless defined; |
292
|
60
|
50
|
|
|
|
117
|
$_ = String::Tools::stringify($_) if ref; |
293
|
60
|
|
|
|
|
114
|
my $quote2 = $self->get('quote2'); |
294
|
60
|
|
33
|
|
|
216
|
my ( $open, $close ) = $self->_get_delim( shift // $quote2 ); |
295
|
|
|
|
|
|
|
|
296
|
60
|
|
|
|
|
92
|
my @sigils; |
297
|
60
|
50
|
|
|
|
115
|
if ( my $sigils = $self->get('sigils') ) { |
298
|
60
|
|
|
|
|
225
|
push @sigils, split //, $sigils; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# quote char(s), sigils, and backslash. |
302
|
60
|
|
|
|
|
134
|
$self = $self->set( encode => $self->get('encode2') ); |
303
|
60
|
|
|
|
|
172
|
my $to_encode = $self->_to_encode( $open, $close, @sigils ); |
304
|
60
|
|
|
|
|
602
|
s/([$to_encode])/$self->_encode_char($1)/eg; |
|
179
|
|
|
|
|
382
|
|
305
|
|
|
|
|
|
|
|
306
|
60
|
50
|
|
|
|
170
|
if ( $quote2 ne $open ) { |
307
|
0
|
0
|
|
|
|
0
|
if ( $open =~ /\w/ ) { |
308
|
0
|
|
|
|
|
0
|
$open = ' ' . $open; |
309
|
0
|
|
|
|
|
0
|
$close = ' ' . $close; |
310
|
|
|
|
|
|
|
} |
311
|
0
|
|
|
|
|
0
|
$open = $self->get('q2') . $open; |
312
|
|
|
|
|
|
|
} |
313
|
|
|
|
|
|
|
|
314
|
60
|
|
|
|
|
428
|
return sprintf '%s%s%s', $open, $_, $close; |
315
|
|
|
|
|
|
|
} |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
### Scalar: string ### |
320
|
|
|
|
|
|
|
|
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
__PACKAGE__->set( |
323
|
|
|
|
|
|
|
# String options |
324
|
|
|
|
|
|
|
quote => undef, # Auto |
325
|
|
|
|
|
|
|
quote1 => "'", |
326
|
|
|
|
|
|
|
#_tr1 => q!tr\\'\\'\\!, |
327
|
|
|
|
|
|
|
quote2 => '"', |
328
|
|
|
|
|
|
|
#_tr2 => q!tr\\"\\"\\!, |
329
|
|
|
|
|
|
|
q1 => 'q', |
330
|
|
|
|
|
|
|
q2 => 'qq', |
331
|
|
|
|
|
|
|
sigils => '$@', |
332
|
|
|
|
|
|
|
longstr => 1_000, |
333
|
|
|
|
|
|
|
encode1 => { |
334
|
|
|
|
|
|
|
0x5c => '\\\\', |
335
|
|
|
|
|
|
|
|
336
|
|
|
|
|
|
|
byte => '\\%c', |
337
|
|
|
|
|
|
|
}, |
338
|
|
|
|
|
|
|
encode2 => { |
339
|
|
|
|
|
|
|
map( { ord( eval qq!"$_"! ) => $_ } qw( \0 \a \b \t \n \f \r \e ) ), |
340
|
|
|
|
|
|
|
#0x00 => '\\0', |
341
|
|
|
|
|
|
|
#0x07 => '\\a', |
342
|
|
|
|
|
|
|
#0x08 => '\\b', |
343
|
|
|
|
|
|
|
#0x09 => '\\t', |
344
|
|
|
|
|
|
|
#0x0a => '\\n', |
345
|
|
|
|
|
|
|
#0x0c => '\\f', |
346
|
|
|
|
|
|
|
#0x0d => '\\r', |
347
|
|
|
|
|
|
|
#0x1b => '\\e', |
348
|
|
|
|
|
|
|
0x5c => '\\\\', |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
also => '[:cntrl:]', |
351
|
|
|
|
|
|
|
byte => '\\x%02x', |
352
|
|
|
|
|
|
|
#utf => 8, |
353
|
|
|
|
|
|
|
wide => '\\x{%04x}', |
354
|
|
|
|
|
|
|
#vwide => '\\x{%06x}', |
355
|
|
|
|
|
|
|
}, |
356
|
|
|
|
|
|
|
|
357
|
|
|
|
|
|
|
do { |
358
|
5
|
|
|
5
|
|
42
|
no warnings 'qw'; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
10603
|
|
359
|
|
|
|
|
|
|
# To silence the warnings: |
360
|
|
|
|
|
|
|
# Possible attempt to put comments in qw() list |
361
|
|
|
|
|
|
|
# Possible attempt to separate words with commas |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
qpairs => [ qw\ () <> [] {} \ ], |
364
|
|
|
|
|
|
|
qquotes => [ |
365
|
|
|
|
|
|
|
# Punctuation, excluding ", ', \, and _ |
366
|
|
|
|
|
|
|
qw\ ! # % & * + , - . / : ; = ? ^ | ~ $ @ ` \ |
367
|
|
|
|
|
|
|
], |
368
|
|
|
|
|
|
|
}, |
369
|
|
|
|
|
|
|
); |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
|
372
|
|
|
|
|
|
|
sub stringify { |
373
|
422
|
|
|
422
|
1
|
10075
|
my $self = &self; |
374
|
422
|
50
|
|
|
|
850
|
local $_ = shift if @_; |
375
|
422
|
50
|
|
|
|
672
|
return $self->undefify unless defined; |
376
|
422
|
50
|
|
|
|
598
|
$_ = String::Tools::stringify($_) if ref; |
377
|
422
|
|
|
|
|
465
|
local $@ = undef; |
378
|
|
|
|
|
|
|
|
379
|
422
|
|
|
|
|
742
|
my ( $quote, $quote1, $quote2 ) = $self->get(qw( quote quote1 quote2 )); |
380
|
422
|
50
|
|
|
|
747
|
if ($quote) { |
381
|
0
|
0
|
0
|
|
|
0
|
return $self->stringify1($_) if $quote1 && $quote1 eq $quote; |
382
|
0
|
0
|
0
|
|
|
0
|
return $self->stringify2($_) if $quote2 && $quote2 eq $quote; |
383
|
0
|
|
|
|
|
0
|
Carp::croak("Bad setting for quote: $quote"); |
384
|
|
|
|
|
|
|
} |
385
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
# Long strings or strings with special characters |
387
|
422
|
|
|
|
|
649
|
my $longstr = $self->get('longstr'); |
388
|
422
|
|
|
|
|
652
|
my $encode2 = $self->get('encode2'); |
389
|
422
|
|
33
|
|
|
1150
|
my $also = $encode2 && $encode2->{also}; |
390
|
422
|
100
|
33
|
|
|
2791
|
return $self->stringify2($_) |
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
391
|
|
|
|
|
|
|
if ( ( $longstr && $longstr < length() ) || ( $also && /[$also]/ ) ); |
392
|
|
|
|
|
|
|
|
393
|
410
|
|
|
|
|
672
|
my $tr1 = $self->get('_tr1'); |
394
|
410
|
50
|
|
|
|
1198
|
$self = $self->set( _tr1 => $tr1 = "tr\\$quote1\\$quote1\\" ) |
395
|
|
|
|
|
|
|
if ( not $tr1 ); |
396
|
410
|
|
50
|
|
|
20231
|
my $single_quotes = eval $tr1 // die $@; |
397
|
410
|
100
|
|
|
|
1621
|
return $self->stringify1($_) unless $single_quotes; |
398
|
|
|
|
|
|
|
|
399
|
21
|
|
|
|
|
127
|
my ( $sigils, $tr2 ) = $self->get(qw( sigils _tr2 )); |
400
|
21
|
50
|
|
|
|
114
|
$self = $self->set( _tr2 => $tr2 = "tr\\$quote2$sigils\\$quote2$sigils\\" ) |
401
|
|
|
|
|
|
|
if ( not $tr2 ); |
402
|
21
|
|
50
|
|
|
905
|
my $double_quotes = eval $tr2 // die $@; |
403
|
21
|
100
|
|
|
|
108
|
return $self->stringify2($_) unless $double_quotes; |
404
|
|
|
|
|
|
|
|
405
|
1
|
|
|
|
|
5
|
return $self->stringify1( $_, $self->_find_q($_) ); |
406
|
|
|
|
|
|
|
} |
407
|
|
|
|
|
|
|
|
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
|
410
|
|
|
|
|
|
|
### Scalar: number ### |
411
|
|
|
|
|
|
|
# Adapted from Perl FAQ "How can I output my numbers with commas added?" |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
|
414
|
|
|
|
|
|
|
__PACKAGE__->set( |
415
|
|
|
|
|
|
|
# Number options |
416
|
|
|
|
|
|
|
infinite => "'inf'", |
417
|
|
|
|
|
|
|
-infinite => "'-inf'", |
418
|
|
|
|
|
|
|
nonnumber => "'nan'", |
419
|
|
|
|
|
|
|
num_sep => '_', |
420
|
|
|
|
|
|
|
); |
421
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
|
423
|
|
|
|
|
|
|
sub is_numeric { |
424
|
3414
|
|
|
3414
|
1
|
4282
|
my $self = &self; |
425
|
3414
|
50
|
|
|
|
5832
|
local $_ = shift if @_; |
426
|
|
|
|
|
|
|
|
427
|
3414
|
50
|
|
|
|
4608
|
return undef unless defined; |
428
|
|
|
|
|
|
|
|
429
|
3414
|
50
|
|
|
|
4388
|
if (ref) { |
430
|
0
|
0
|
|
|
|
0
|
if ( my $method = $self->overloaded($_) ) { |
431
|
0
|
|
|
|
|
0
|
$_ = $_->$method(); |
432
|
|
|
|
|
|
|
} |
433
|
|
|
|
|
|
|
else { |
434
|
0
|
|
|
|
|
0
|
return ''; |
435
|
|
|
|
|
|
|
} |
436
|
|
|
|
|
|
|
} |
437
|
|
|
|
|
|
|
|
438
|
3414
|
|
|
|
|
5390
|
return LooksLike::numeric($_); |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
sub numify { |
443
|
384
|
|
|
384
|
1
|
34931
|
my $self = &self; |
444
|
384
|
50
|
|
|
|
738
|
local $_ = shift if @_; |
445
|
|
|
|
|
|
|
|
446
|
384
|
100
|
|
|
|
591
|
return $self->undefify unless defined; |
447
|
|
|
|
|
|
|
|
448
|
383
|
100
|
|
|
|
594
|
if ( $self->is_numeric($_) ) { |
|
|
100
|
|
|
|
|
|
449
|
369
|
50
|
|
|
|
4092
|
return $_ unless my $sep = $self->get('num_sep'); |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
# Fractional portion |
452
|
369
|
|
|
|
|
995
|
s{^(\s*[-+]?\d*\.\d\d)(\d+)} [${1}$sep${2}]; |
453
|
369
|
|
|
|
|
1555
|
1 while s{^(\s*[-+]?\d*\.(?:\d+$sep)+\d\d\d)(\d+)}[${1}$sep${2}]; |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
# Whole portion |
456
|
369
|
|
|
|
|
1276
|
1 while s{^(\s*[-+]?\d+)(\d{3})} [${1}$sep${2}]; |
457
|
|
|
|
|
|
|
|
458
|
369
|
|
|
|
|
1150
|
return $_; |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
elsif ( LooksLike::number($_) ) { |
461
|
12
|
|
|
|
|
263
|
return LooksLike::representation( |
462
|
|
|
|
|
|
|
$_, |
463
|
|
|
|
|
|
|
"infinity" => $self->get('infinite'), |
464
|
|
|
|
|
|
|
"-infinity" => $self->get('-infinite'), |
465
|
|
|
|
|
|
|
"nan" => $self->get('nonnumber') |
466
|
|
|
|
|
|
|
); |
467
|
|
|
|
|
|
|
} |
468
|
|
|
|
|
|
|
|
469
|
2
|
|
|
|
|
303
|
return $self->get('nonnumber'); |
470
|
|
|
|
|
|
|
} |
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
### Scalar ### |
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
|
477
|
|
|
|
|
|
|
__PACKAGE__->set( |
478
|
|
|
|
|
|
|
# Scalar options |
479
|
|
|
|
|
|
|
scalar_ref => '\do{1;$_}', |
480
|
|
|
|
|
|
|
); |
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
|
483
|
|
|
|
|
|
|
sub scalarify { |
484
|
552
|
|
|
552
|
1
|
18925
|
my $self = &self; |
485
|
552
|
50
|
|
|
|
1157
|
local $_ = shift if @_; |
486
|
|
|
|
|
|
|
|
487
|
552
|
|
100
|
|
|
969
|
my $value = $self->_cache_get($_) // $self->_scalarify($_); |
488
|
552
|
100
|
|
|
|
10964
|
$self->isa( scalar caller ) |
489
|
|
|
|
|
|
|
? $self->_cache_add( $_ => $value ) |
490
|
|
|
|
|
|
|
: $self->_cache_reset($_); |
491
|
552
|
|
|
|
|
1124
|
return $value; |
492
|
|
|
|
|
|
|
} |
493
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
sub _scalarify { |
495
|
546
|
|
|
546
|
|
703
|
my $self = &self; |
496
|
546
|
50
|
|
|
|
1039
|
local $_ = shift if @_; |
497
|
|
|
|
|
|
|
|
498
|
546
|
100
|
|
|
|
914
|
return $self->undefify unless defined $_; |
499
|
|
|
|
|
|
|
|
500
|
526
|
100
|
|
|
|
1062
|
if ( defined( my $blessed = Scalar::Util::blessed($_) ) ) { |
501
|
|
|
|
|
|
|
return |
502
|
36
|
100
|
|
|
|
93
|
$blessed eq 'Regexp' ? $self->regexpify($_) |
503
|
|
|
|
|
|
|
: $self->objectify($_); |
504
|
|
|
|
|
|
|
} |
505
|
|
|
|
|
|
|
|
506
|
490
|
|
|
|
|
739
|
my $ref = Scalar::Util::reftype $_; |
507
|
490
|
100
|
|
|
|
685
|
if ( not $ref ) { |
508
|
|
|
|
|
|
|
# Handle GLOB, LVALUE, and VSTRING |
509
|
384
|
|
|
|
|
637
|
my $ref2 = ref \$_; |
510
|
|
|
|
|
|
|
return |
511
|
384
|
100
|
|
|
|
1417
|
$ref2 eq 'GLOB' ? $self->globify($_) |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
512
|
|
|
|
|
|
|
: $ref2 eq 'LVALUE' ? $self->lvalueify($_) |
513
|
|
|
|
|
|
|
: $ref2 eq 'VSTRING' ? $self->vstringify($_) |
514
|
|
|
|
|
|
|
: $ref2 eq 'SCALAR' ? ( |
515
|
|
|
|
|
|
|
LooksLike::number($_) |
516
|
|
|
|
|
|
|
? $self->numify($_) |
517
|
|
|
|
|
|
|
: $self->stringify($_) |
518
|
|
|
|
|
|
|
) |
519
|
|
|
|
|
|
|
: $self->stringify($_); |
520
|
|
|
|
|
|
|
} |
521
|
|
|
|
|
|
|
|
522
|
|
|
|
|
|
|
return |
523
|
|
|
|
|
|
|
$ref eq 'ARRAY' ? $self->arrayify(@$_) |
524
|
|
|
|
|
|
|
: $ref eq 'CODE' ? $self->codeify($_) |
525
|
|
|
|
|
|
|
: $ref eq 'FORMAT' ? $self->formatify($_) |
526
|
|
|
|
|
|
|
: $ref eq 'HASH' ? $self->hashify($_) |
527
|
|
|
|
|
|
|
: $ref eq 'IO' ? $self->ioify($_) |
528
|
|
|
|
|
|
|
: $ref eq 'REF' ? $self->refify($$_) |
529
|
|
|
|
|
|
|
: $ref eq 'REGEXP' ? $self->regexpify($_) # ??? |
530
|
106
|
50
|
|
|
|
463
|
: do { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
531
|
18
|
|
33
|
|
|
58
|
my $reference = $self->get( lc($ref) . '_reference' ) |
532
|
|
|
|
|
|
|
|| $self->get('reference'); |
533
|
|
|
|
|
|
|
|
534
|
18
|
50
|
|
|
|
101
|
$ref eq 'GLOB' ? _subst( $reference, $self->globify($$_) ) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
535
|
|
|
|
|
|
|
: $ref eq 'LVALUE' ? _subst( $reference, $self->lvalueify($$_) ) |
536
|
|
|
|
|
|
|
: $ref eq 'SCALAR' ? _subst( $reference, $self->scalarify($$_) ) |
537
|
|
|
|
|
|
|
: $ref eq 'VSTRING' ? _subst( $reference, $self->vstringify($$_) ) |
538
|
|
|
|
|
|
|
: $self->objectify($_) |
539
|
|
|
|
|
|
|
; |
540
|
|
|
|
|
|
|
}; |
541
|
|
|
|
|
|
|
} |
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
|
545
|
|
|
|
|
|
|
### Scalar: LValue ### |
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
__PACKAGE__->set( |
549
|
|
|
|
|
|
|
# LValue options |
550
|
|
|
|
|
|
|
lvalue => 'substr($lvalue, 0)', |
551
|
|
|
|
|
|
|
); |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
|
554
|
|
|
|
|
|
|
sub lvalueify { |
555
|
4
|
|
|
4
|
1
|
6
|
my $self = &self; |
556
|
4
|
|
|
|
|
7
|
return _subst( $self->get('lvalue'), lvalue => $self->stringify(shift) ); |
557
|
|
|
|
|
|
|
} |
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
|
561
|
|
|
|
|
|
|
### Scalar: VString ### |
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
|
564
|
|
|
|
|
|
|
__PACKAGE__->set( |
565
|
|
|
|
|
|
|
# VString options |
566
|
|
|
|
|
|
|
vformat => 'v%vd', |
567
|
|
|
|
|
|
|
#vformat => 'v%*vd', |
568
|
|
|
|
|
|
|
#vsep => '.', |
569
|
|
|
|
|
|
|
); |
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
|
572
|
|
|
|
|
|
|
sub vstringify { |
573
|
4
|
|
|
4
|
1
|
8
|
my $self = &self; |
574
|
4
|
50
|
|
|
|
9
|
if ( defined( my $vsep = $self->get('vsep') ) ) { |
575
|
0
|
|
|
|
|
0
|
return sprintf $self->get('vformat'), $vsep, shift; |
576
|
|
|
|
|
|
|
} else { |
577
|
4
|
|
|
|
|
7
|
return sprintf $self->get('vformat'), shift; |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
} |
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
|
583
|
|
|
|
|
|
|
### Regexp ### |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
|
586
|
|
|
|
|
|
|
__PACKAGE__->set( |
587
|
|
|
|
|
|
|
# Regexp options |
588
|
|
|
|
|
|
|
quote3 => '/', |
589
|
|
|
|
|
|
|
#_tr3 => q!tr\\/\\/\\!, |
590
|
|
|
|
|
|
|
q3 => 'qr', |
591
|
|
|
|
|
|
|
|
592
|
|
|
|
|
|
|
encode3 => { |
593
|
|
|
|
|
|
|
map( { ord( eval qq!"$_"! ) => $_ } qw( \0 \a \t \n \f \r \e ) ), |
594
|
|
|
|
|
|
|
#0x00 => '\\0', |
595
|
|
|
|
|
|
|
#0x07 => '\\a', |
596
|
|
|
|
|
|
|
#0x09 => '\\t', |
597
|
|
|
|
|
|
|
#0x0a => '\\n', |
598
|
|
|
|
|
|
|
#0x0c => '\\f', |
599
|
|
|
|
|
|
|
#0x0d => '\\r', |
600
|
|
|
|
|
|
|
#0x1b => '\\e', |
601
|
|
|
|
|
|
|
|
602
|
|
|
|
|
|
|
also => '[:cntrl:]', |
603
|
|
|
|
|
|
|
byte => '\\x%02x', |
604
|
|
|
|
|
|
|
wide => '\\x{%04x}', |
605
|
|
|
|
|
|
|
#vwide => '\\x{%06x}', |
606
|
|
|
|
|
|
|
}, |
607
|
|
|
|
|
|
|
); |
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
|
610
|
|
|
|
|
|
|
sub regexpify { |
611
|
4
|
|
|
4
|
1
|
5
|
my $self = &self; |
612
|
4
|
50
|
|
|
|
10
|
local $_ = shift if @_; |
613
|
4
|
|
|
|
|
7
|
local $@ = undef; |
614
|
|
|
|
|
|
|
|
615
|
4
|
|
|
|
|
6
|
my ( $quote3, $tr3 ) = $self->get(qw( quote3 _tr3 )); |
616
|
4
|
50
|
|
|
|
16
|
$self = $self->set( _tr3 => $tr3 = "tr\\$quote3\\$quote3\\" ) |
617
|
|
|
|
|
|
|
if ( not $tr3 ); |
618
|
4
|
|
50
|
|
|
219
|
my $quoter = eval $tr3 // die $@; |
619
|
4
|
50
|
33
|
|
|
24
|
my ( $open, $close ) |
620
|
|
|
|
|
|
|
= $self->_get_delim( |
621
|
|
|
|
|
|
|
shift // $quoter ? $self->_find_q($_) : $self->get('quote3') ); |
622
|
|
|
|
|
|
|
|
623
|
|
|
|
|
|
|
# Everything but the quotes should be escaped already. |
624
|
4
|
|
|
|
|
8
|
$self = $self->set( encode => $self->get('encode3') ); |
625
|
4
|
|
|
|
|
12
|
my $to_encode = $self->_to_encode( $open, $close ); |
626
|
4
|
|
|
|
|
37
|
s/([$to_encode])/$self->_encode_char($1)/eg; |
|
0
|
|
|
|
|
0
|
|
627
|
|
|
|
|
|
|
|
628
|
4
|
50
|
|
|
|
11
|
if ( $open =~ /\w/ ) { |
629
|
0
|
|
|
|
|
0
|
$open = ' ' . $open; |
630
|
0
|
|
|
|
|
0
|
$close = ' ' . $close; |
631
|
|
|
|
|
|
|
} |
632
|
|
|
|
|
|
|
|
633
|
4
|
|
|
|
|
9
|
$open = $self->get('q3') . $open; |
634
|
|
|
|
|
|
|
|
635
|
4
|
|
|
|
|
25
|
return sprintf '%s%s%s', $open, $_, $close; |
636
|
|
|
|
|
|
|
} |
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
### List/Array ### |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
sub listify { |
644
|
24
|
|
|
24
|
1
|
44
|
my $self = &self; |
645
|
24
|
|
|
|
|
36
|
my @values; |
646
|
24
|
|
|
|
|
73
|
for ( my $i = 0; $i < @_; $i++ ) { |
647
|
116
|
|
|
|
|
184
|
my $value = $_[$i]; |
648
|
116
|
|
|
|
|
265
|
$self = $self->_push_position("[$i]"); |
649
|
116
|
|
|
|
|
209
|
push @values, $self->scalarify($value); |
650
|
116
|
|
|
|
|
194
|
$self->_pop_position; |
651
|
|
|
|
|
|
|
} |
652
|
24
|
|
|
|
|
72
|
return join( $self->get('list_sep'), @values ); |
653
|
|
|
|
|
|
|
} |
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
|
658
|
|
|
|
|
|
|
__PACKAGE__->set( |
659
|
|
|
|
|
|
|
# Array options |
660
|
|
|
|
|
|
|
array_ref => '[$_]', |
661
|
|
|
|
|
|
|
); |
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
sub arrayify { |
665
|
24
|
|
|
24
|
1
|
51
|
my $self = &self; |
666
|
24
|
|
|
|
|
51
|
return _subst( $self->get('array_ref'), $self->listify(@_) ); |
667
|
|
|
|
|
|
|
} |
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
### Hash ### |
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
|
674
|
|
|
|
|
|
|
sub is_keyword { |
675
|
326
|
|
|
326
|
1
|
459
|
my $self = &self; |
676
|
|
|
|
|
|
|
|
677
|
326
|
|
|
|
|
508
|
my $keyword_set = $self->get('keyword_set'); |
678
|
326
|
100
|
|
|
|
568
|
if ( not $keyword_set ) { |
679
|
63
|
|
50
|
|
|
111
|
my $keywords = $self->get('keywords') // []; |
680
|
63
|
50
|
|
|
|
134
|
return unless @$keywords; |
681
|
63
|
|
|
|
|
95
|
$keyword_set = { map { $_ => 1 } @$keywords }; |
|
63
|
|
|
|
|
201
|
|
682
|
63
|
|
|
|
|
121
|
$self->{keyword_set} = $keyword_set; |
683
|
|
|
|
|
|
|
} |
684
|
326
|
|
|
|
|
1721
|
return exists $keyword_set->{ +shift }; |
685
|
|
|
|
|
|
|
} |
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
sub keyify { |
689
|
493
|
|
|
493
|
1
|
657
|
my $self = &self; |
690
|
493
|
50
|
|
|
|
965
|
local $_ = shift if @_; |
691
|
|
|
|
|
|
|
|
692
|
493
|
50
|
|
|
|
772
|
return $self->undefify unless defined; |
693
|
493
|
50
|
|
|
|
700
|
return $_ if ref; |
694
|
|
|
|
|
|
|
|
695
|
493
|
100
|
33
|
|
|
745
|
if ( $self->is_numeric($_) ) { |
|
|
100
|
66
|
|
|
|
|
696
|
167
|
|
|
|
|
2146
|
return $self->numify($_); |
697
|
|
|
|
|
|
|
} elsif ( length() < $self->get('longstr') |
698
|
|
|
|
|
|
|
&& !$self->is_keyword($_) |
699
|
|
|
|
|
|
|
&& /\A-?[[:alpha:]_]\w*\z/ ) |
700
|
|
|
|
|
|
|
{ |
701
|
|
|
|
|
|
|
# If the key would be autoquoted by the fat-comma (=>), |
702
|
|
|
|
|
|
|
# then there is no need to quote it. |
703
|
|
|
|
|
|
|
|
704
|
294
|
|
|
|
|
741
|
return "$_"; # Make sure it's stringified. |
705
|
|
|
|
|
|
|
} |
706
|
32
|
|
|
|
|
104
|
return $self->stringify($_); |
707
|
|
|
|
|
|
|
} |
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
|
712
|
|
|
|
|
|
|
sub keysort($$); |
713
|
|
|
|
|
|
|
BEGIN { |
714
|
5
|
|
|
5
|
|
41
|
no warnings 'qw'; |
|
5
|
|
|
|
|
30
|
|
|
5
|
|
|
|
|
587
|
|
715
|
5
|
50
|
|
5
|
|
102
|
my $a_cmp__b |
716
|
|
|
|
|
|
|
= $^V >= v5.16.0 |
717
|
|
|
|
|
|
|
? 'CORE::fc($a) cmp CORE::fc($b)' |
718
|
|
|
|
|
|
|
: 'lc($a) cmp lc($b)'; |
719
|
5
|
|
|
|
|
44
|
my $keysort = String::Tools::stitch(qw( |
720
|
|
|
|
|
|
|
sub keysort($$) { |
721
|
|
|
|
|
|
|
my ( $a, $b ) = @_; |
722
|
|
|
|
|
|
|
my $numa = Datify->is_numeric($a); |
723
|
|
|
|
|
|
|
my $numb = Datify->is_numeric($b); |
724
|
|
|
|
|
|
|
return( |
725
|
|
|
|
|
|
|
( $numa && $numb ? $a <=> $b |
726
|
|
|
|
|
|
|
: $numa ? -1 |
727
|
|
|
|
|
|
|
: $numb ? +1 |
728
|
|
|
|
|
|
|
: $a_cmp__b ) |
729
|
|
|
|
|
|
|
|| $a cmp $b |
730
|
|
|
|
|
|
|
); |
731
|
|
|
|
|
|
|
} |
732
|
|
|
|
|
|
|
)); |
733
|
5
|
|
|
|
|
3987
|
$keysort = String::Tools::subst( $keysort, a_cmp__b => $a_cmp__b ); |
734
|
5
|
50
|
50
|
1269
|
1
|
6870
|
eval($keysort) or $@ and die $@; |
|
1269
|
|
100
|
|
|
2613
|
|
|
1269
|
|
|
|
|
2263
|
|
|
1269
|
|
|
|
|
30822
|
|
|
1269
|
|
|
|
|
32183
|
|
735
|
|
|
|
|
|
|
} |
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
|
739
|
|
|
|
|
|
|
sub hashkeys { |
740
|
58
|
|
|
58
|
1
|
77
|
my $self = shift; |
741
|
58
|
|
|
|
|
75
|
my $hash = shift; |
742
|
|
|
|
|
|
|
|
743
|
58
|
|
|
|
|
178
|
my @keys = keys %$hash; |
744
|
58
|
50
|
|
|
|
99
|
if ( my $ref = ref( my $keyfilter = $self->get('keyfilter') ) ) { |
745
|
0
|
|
|
|
|
0
|
my $keyfilternot = !$self->get('keyfilterdefault'); |
746
|
0
|
|
|
|
|
0
|
my $keyfilterdefault = !$keyfilternot; |
747
|
0
|
0
|
0
|
|
|
0
|
if ( $ref eq 'ARRAY' || $ref eq 'HASH' ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
748
|
|
|
|
|
|
|
my %keyfilterhash |
749
|
|
|
|
|
|
|
= $ref eq 'ARRAY' |
750
|
0
|
0
|
|
|
|
0
|
? ( map { $_ => $keyfilternot } @$keyfilter ) |
|
0
|
|
|
|
|
0
|
|
751
|
|
|
|
|
|
|
: %$keyfilter; |
752
|
|
|
|
|
|
|
$self->{keyfilter} = $keyfilter = sub { |
753
|
|
|
|
|
|
|
exists $keyfilterhash{$_} |
754
|
0
|
0
|
|
0
|
|
0
|
? $keyfilterhash{$_} |
755
|
|
|
|
|
|
|
: $keyfilterdefault; |
756
|
0
|
|
|
|
|
0
|
}; |
757
|
|
|
|
|
|
|
} elsif ( $ref eq 'CODE' ) { |
758
|
|
|
|
|
|
|
# No-op, just use the code provided |
759
|
|
|
|
|
|
|
} elsif ( $ref eq 'Regexp' ) { |
760
|
0
|
|
|
|
|
0
|
my $keyfilterregexp = $keyfilter; |
761
|
|
|
|
|
|
|
$self->{keyfilter} = $keyfilter = sub { |
762
|
0
|
0
|
|
0
|
|
0
|
m/$keyfilterregexp/ ? $keyfilternot : $keyfilterdefault; |
763
|
0
|
|
|
|
|
0
|
}; |
764
|
|
|
|
|
|
|
} elsif ( $ref eq 'SCALAR' ) { |
765
|
0
|
|
|
|
|
0
|
my $keyfiltervalue = $$keyfilter; |
766
|
0
|
|
|
0
|
|
0
|
$self->{keyfilter} = $keyfilter = sub {$keyfiltervalue}; |
|
0
|
|
|
|
|
0
|
|
767
|
|
|
|
|
|
|
} |
768
|
0
|
|
|
|
|
0
|
@keys = grep { $keyfilter->() } @keys; |
|
0
|
|
|
|
|
0
|
|
769
|
|
|
|
|
|
|
} |
770
|
58
|
50
|
|
|
|
109
|
if ( my $keymap = $self->get('keymap') ) { |
771
|
0
|
|
|
|
|
0
|
@keys = map { $self->$keymap($_) } @keys; |
|
0
|
|
|
|
|
0
|
|
772
|
|
|
|
|
|
|
} |
773
|
58
|
50
|
|
|
|
108
|
if ( my $keysort = $self->get('keysort') ) { |
774
|
58
|
|
|
|
|
767
|
@keys = sort $keysort @keys; |
775
|
|
|
|
|
|
|
} |
776
|
58
|
|
|
|
|
265
|
return @keys; |
777
|
|
|
|
|
|
|
} |
778
|
|
|
|
|
|
|
|
779
|
|
|
|
|
|
|
sub hashkeyvals { |
780
|
28
|
|
|
28
|
0
|
39
|
my $self = shift; |
781
|
28
|
|
|
|
|
43
|
my $hash = shift; |
782
|
|
|
|
|
|
|
|
783
|
28
|
|
|
|
|
64
|
return map { $_ => $hash->{$_} } $self->hashkeys($hash); |
|
292
|
|
|
|
|
519
|
|
784
|
|
|
|
|
|
|
} |
785
|
|
|
|
|
|
|
|
786
|
|
|
|
|
|
|
|
787
|
|
|
|
|
|
|
sub pairify { |
788
|
28
|
|
|
28
|
1
|
52
|
my $self = &self; |
789
|
28
|
50
|
|
|
|
69
|
if (1 == @_) { |
790
|
28
|
|
|
|
|
69
|
my $ref = Scalar::Util::reftype $_[0]; |
791
|
28
|
50
|
|
|
|
107
|
@_ = $ref eq 'ARRAY' ? @{ +shift } |
|
0
|
50
|
|
|
|
0
|
|
792
|
|
|
|
|
|
|
: $ref eq 'HASH' ? $self->hashkeyvals(shift) |
793
|
|
|
|
|
|
|
: @_; |
794
|
|
|
|
|
|
|
} |
795
|
|
|
|
|
|
|
# Use for loop in order to preserve the order of @_, |
796
|
|
|
|
|
|
|
# rather than each %{ { @_ } }, which would mix-up the order. |
797
|
28
|
|
|
|
|
53
|
my @list; |
798
|
28
|
|
|
|
|
62
|
my $pair = $self->get('pair'); |
799
|
28
|
|
|
|
|
97
|
for ( my $i = 0; $i < @_ - 1; $i += 2 ) { |
800
|
292
|
|
|
|
|
16426
|
my ( $k, $v ) = @_[ $i, $i + 1 ]; |
801
|
292
|
|
|
|
|
574
|
my $key = $self->keyify($k); |
802
|
292
|
|
|
|
|
673
|
$self = $self->_push_position("{$key}"); |
803
|
292
|
|
|
|
|
487
|
my $val = $self->scalarify($v); |
804
|
292
|
|
|
|
|
591
|
$self->_pop_position; |
805
|
292
|
|
|
|
|
555
|
push @list, _subst( $pair, key => $key, value => $val ); |
806
|
|
|
|
|
|
|
} |
807
|
28
|
|
|
|
|
1627
|
return join( $self->get('list_sep'), @list ); |
808
|
|
|
|
|
|
|
} |
809
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
|
811
|
|
|
|
|
|
|
|
812
|
|
|
|
|
|
|
|
813
|
|
|
|
|
|
|
__PACKAGE__->set( |
814
|
|
|
|
|
|
|
# Hash options |
815
|
|
|
|
|
|
|
hash_ref => '{$_}', |
816
|
|
|
|
|
|
|
pair => '$key => $value', |
817
|
|
|
|
|
|
|
keymap => undef, |
818
|
|
|
|
|
|
|
keysort => \&Datify::keysort, |
819
|
|
|
|
|
|
|
keyfilter => undef, |
820
|
|
|
|
|
|
|
keyfilterdefault => 1, |
821
|
|
|
|
|
|
|
keywords => [qw(undef)], |
822
|
|
|
|
|
|
|
#keyword_set => { 'undef' => 1 }, |
823
|
|
|
|
|
|
|
); |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
sub hashify { |
827
|
28
|
|
|
28
|
1
|
52
|
my $self = &self; |
828
|
28
|
|
|
|
|
68
|
return _subst( $self->get('hash_ref'), $self->pairify(@_) ); |
829
|
|
|
|
|
|
|
} |
830
|
|
|
|
|
|
|
|
831
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
|
833
|
|
|
|
|
|
|
### Objects ### |
834
|
|
|
|
|
|
|
|
835
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
sub overloaded { |
837
|
32
|
|
|
32
|
1
|
44
|
my $self = &self; |
838
|
32
|
50
|
|
|
|
61
|
my $object = @_ ? shift : $_; |
839
|
|
|
|
|
|
|
|
840
|
32
|
50
|
33
|
|
|
152
|
return unless defined( Scalar::Util::blessed($object) ) |
841
|
|
|
|
|
|
|
&& overload::Overloaded($object); |
842
|
|
|
|
|
|
|
|
843
|
0
|
|
0
|
|
|
0
|
my $overloads = $self->get('overloads') || []; |
844
|
0
|
|
|
|
|
0
|
foreach my $overload (@$overloads) { |
845
|
0
|
0
|
|
|
|
0
|
if ( my $method = overload::Method( $object => $overload ) ) { |
846
|
0
|
|
|
|
|
0
|
return $method; |
847
|
|
|
|
|
|
|
} |
848
|
|
|
|
|
|
|
} |
849
|
0
|
|
|
|
|
0
|
return; |
850
|
|
|
|
|
|
|
} |
851
|
|
|
|
|
|
|
|
852
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
|
854
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
__PACKAGE__->set( |
856
|
|
|
|
|
|
|
# Object options |
857
|
|
|
|
|
|
|
overloads => [ '""', '0+' ], |
858
|
|
|
|
|
|
|
object => 'bless($data, $class_str)', |
859
|
|
|
|
|
|
|
#object => '$class->new($data)', |
860
|
|
|
|
|
|
|
#object => '$class=$data', |
861
|
|
|
|
|
|
|
); |
862
|
|
|
|
|
|
|
|
863
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
sub objectify { |
865
|
32
|
|
|
32
|
1
|
44
|
my $self = &self; |
866
|
32
|
50
|
|
|
|
61
|
my $object = @_ ? shift : $_; |
867
|
|
|
|
|
|
|
|
868
|
32
|
50
|
|
|
|
77
|
return $self->scalarify($object) |
869
|
|
|
|
|
|
|
unless defined( my $class = Scalar::Util::blessed($object) ); |
870
|
|
|
|
|
|
|
|
871
|
32
|
|
|
|
|
44
|
my $data; |
872
|
32
|
50
|
|
|
|
55
|
if (0) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
873
|
0
|
|
|
|
|
0
|
} elsif ( my $code = $self->_find_handler($class) ) { |
874
|
0
|
|
|
|
|
0
|
return $self->$code($object); |
875
|
|
|
|
|
|
|
} elsif ( my $method = $self->overloaded($object) ) { |
876
|
0
|
|
|
|
|
0
|
$data = $self->scalarify( $object->$method() ); |
877
|
|
|
|
|
|
|
} elsif ( my $attrkeyvals = $object->can('_attrkeyvals') ) { |
878
|
|
|
|
|
|
|
# TODO: Look this up via meta-objects |
879
|
0
|
|
|
|
|
0
|
$data = $self->hashify( $object->$attrkeyvals() ); |
880
|
|
|
|
|
|
|
} else { |
881
|
32
|
|
|
|
|
1457
|
$data = Scalar::Util::reftype $object; |
882
|
|
|
|
|
|
|
|
883
|
32
|
50
|
|
|
|
169
|
$data |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
884
|
|
|
|
|
|
|
= $data eq 'ARRAY' ? $self->arrayify( @$object ) |
885
|
|
|
|
|
|
|
: $data eq 'CODE' ? $self->codeify( $object ) |
886
|
|
|
|
|
|
|
: $data eq 'FORMAT' ? $self->formatify( $object ) |
887
|
|
|
|
|
|
|
: $data eq 'GLOB' ? $self->globify( $object ) |
888
|
|
|
|
|
|
|
: $data eq 'HASH' ? $self->hashify( $object ) |
889
|
|
|
|
|
|
|
: $data eq 'IO' ? $self->ioify( $object ) |
890
|
|
|
|
|
|
|
: $data eq 'REF' ? $self->refify( $$object ) |
891
|
|
|
|
|
|
|
: $data eq 'REGEXP' ? $self->regexpify( $object ) |
892
|
|
|
|
|
|
|
: $data eq 'SCALAR' ? $self->refify( $$object ) |
893
|
|
|
|
|
|
|
: "*UNKNOWN{$data}"; |
894
|
|
|
|
|
|
|
} |
895
|
|
|
|
|
|
|
|
896
|
32
|
|
|
|
|
1858
|
return _subst( |
897
|
|
|
|
|
|
|
$self->get('object'), |
898
|
|
|
|
|
|
|
class_str => $self->stringify($class), |
899
|
|
|
|
|
|
|
class => $class, |
900
|
|
|
|
|
|
|
data => $data |
901
|
|
|
|
|
|
|
); |
902
|
|
|
|
|
|
|
} |
903
|
|
|
|
|
|
|
|
904
|
|
|
|
|
|
|
|
905
|
|
|
|
|
|
|
|
906
|
|
|
|
|
|
|
### Objects: IO ### |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
__PACKAGE__->set( |
910
|
|
|
|
|
|
|
# IO options |
911
|
|
|
|
|
|
|
io => '*$name{IO}', |
912
|
|
|
|
|
|
|
); |
913
|
|
|
|
|
|
|
|
914
|
|
|
|
|
|
|
|
915
|
|
|
|
|
|
|
|
916
|
|
|
|
|
|
|
sub ioify { |
917
|
4
|
|
|
4
|
1
|
8
|
my $self = &self; |
918
|
4
|
50
|
|
|
|
7
|
my $io = @_ ? shift : $_; |
919
|
|
|
|
|
|
|
|
920
|
4
|
|
|
|
|
6
|
my $ioname = 'UNKNOWN'; |
921
|
4
|
|
|
|
|
8
|
foreach my $ioe (qw( IN OUT ERR )) { |
922
|
5
|
|
|
5
|
|
42
|
no strict 'refs'; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
14404
|
|
923
|
8
|
100
|
|
|
|
9
|
if ( *{"main::STD$ioe"}{IO} == $io ) { |
|
8
|
|
|
|
|
28
|
|
924
|
4
|
|
|
|
|
5
|
$ioname = "STD$ioe"; |
925
|
4
|
|
|
|
|
5
|
last; |
926
|
|
|
|
|
|
|
} |
927
|
|
|
|
|
|
|
} |
928
|
|
|
|
|
|
|
# TODO |
929
|
|
|
|
|
|
|
#while ( my ( $name, $glob ) = each %main:: ) { |
930
|
|
|
|
|
|
|
# no strict 'refs'; |
931
|
|
|
|
|
|
|
# if ( defined( *{$glob}{IO} ) && *{$glob}{IO} == $io ) { |
932
|
|
|
|
|
|
|
# keys %main::; # We're done, so reset each() |
933
|
|
|
|
|
|
|
# $ioname = $name; |
934
|
|
|
|
|
|
|
# last; |
935
|
|
|
|
|
|
|
# } |
936
|
|
|
|
|
|
|
#} |
937
|
4
|
|
|
|
|
9
|
return _subst( $self->get('io'), name => $ioname ); |
938
|
|
|
|
|
|
|
} |
939
|
|
|
|
|
|
|
|
940
|
|
|
|
|
|
|
|
941
|
|
|
|
|
|
|
|
942
|
|
|
|
|
|
|
### Other ### |
943
|
|
|
|
|
|
|
|
944
|
|
|
|
|
|
|
|
945
|
|
|
|
|
|
|
__PACKAGE__->set( |
946
|
|
|
|
|
|
|
# Code options |
947
|
|
|
|
|
|
|
code => 'sub {$body}', |
948
|
|
|
|
|
|
|
codename => '\&$codename', |
949
|
|
|
|
|
|
|
body => '...', |
950
|
|
|
|
|
|
|
); |
951
|
|
|
|
|
|
|
|
952
|
|
|
|
|
|
|
|
953
|
|
|
|
|
|
|
sub codeify { |
954
|
8
|
|
|
8
|
1
|
14
|
my $self = &self; |
955
|
|
|
|
|
|
|
|
956
|
8
|
|
|
|
|
15
|
my $template = $self->get('code'); |
957
|
8
|
|
|
|
|
19
|
my %data = ( body => $self->get('body') ); |
958
|
8
|
50
|
33
|
|
|
34
|
if ( @_ && defined( $_[0] ) ) { |
959
|
8
|
|
|
|
|
11
|
local $_ = shift; |
960
|
8
|
50
|
|
|
|
22
|
if ( my $ref = Scalar::Util::reftype($_) ) { |
961
|
8
|
50
|
|
|
|
18
|
if ( $ref eq 'CODE' ) { |
962
|
8
|
100
|
|
|
|
65
|
if ( ( my $subname = Sub::Util::subname($_) ) |
963
|
|
|
|
|
|
|
!~ /\A(?:\w+\::)*__ANON__\z/ ) |
964
|
|
|
|
|
|
|
{ |
965
|
4
|
|
33
|
|
|
13
|
$template = $self->get('codename') // $template; |
966
|
4
|
|
|
|
|
18
|
%data = ( codename => $subname ); |
967
|
|
|
|
|
|
|
} |
968
|
|
|
|
|
|
|
} else { |
969
|
0
|
|
|
|
|
0
|
%data = ( body => $self->scalarify($_) ); |
970
|
|
|
|
|
|
|
} |
971
|
|
|
|
|
|
|
} else { |
972
|
0
|
|
|
|
|
0
|
%data = ( body => $_ ); |
973
|
|
|
|
|
|
|
} |
974
|
|
|
|
|
|
|
} |
975
|
8
|
|
|
|
|
26
|
return _subst( $template, %data ); |
976
|
|
|
|
|
|
|
} |
977
|
|
|
|
|
|
|
|
978
|
|
|
|
|
|
|
|
979
|
|
|
|
|
|
|
|
980
|
|
|
|
|
|
|
|
981
|
|
|
|
|
|
|
__PACKAGE__->set( |
982
|
|
|
|
|
|
|
# Reference options |
983
|
|
|
|
|
|
|
reference => '\\$_', |
984
|
|
|
|
|
|
|
dereference => '$referent->$place', |
985
|
|
|
|
|
|
|
nested => '$referent$place', |
986
|
|
|
|
|
|
|
); |
987
|
|
|
|
|
|
|
|
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
sub refify { |
990
|
52
|
|
|
52
|
1
|
77
|
my $self = &self; |
991
|
52
|
50
|
|
|
|
131
|
local $_ = shift if @_; |
992
|
52
|
|
|
|
|
86
|
return _subst( $self->get('reference'), $self->scalarify($_) ); |
993
|
|
|
|
|
|
|
} |
994
|
|
|
|
|
|
|
|
995
|
|
|
|
|
|
|
|
996
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
__PACKAGE__->set( |
999
|
|
|
|
|
|
|
# Format options |
1000
|
|
|
|
|
|
|
format => "format UNKNOWN =\n.\n", |
1001
|
|
|
|
|
|
|
); |
1002
|
|
|
|
|
|
|
|
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
sub formatify { |
1005
|
4
|
|
|
4
|
1
|
7
|
my $self = &self; |
1006
|
|
|
|
|
|
|
#Carp::croak "Unhandled type: ", ref shift; |
1007
|
4
|
|
|
|
|
7
|
return $self->get('format'); |
1008
|
|
|
|
|
|
|
} |
1009
|
|
|
|
|
|
|
|
1010
|
|
|
|
|
|
|
|
1011
|
|
|
|
|
|
|
|
1012
|
|
|
|
|
|
|
|
1013
|
|
|
|
|
|
|
sub globify { |
1014
|
4
|
|
|
4
|
1
|
8
|
my $self = &self; |
1015
|
4
|
|
|
|
|
12
|
my $name = '' . shift; |
1016
|
4
|
50
|
|
|
|
113
|
if ( $name =~ /^\*$package\::(?:$word|$digits)?$/ ) { |
1017
|
4
|
|
|
|
|
15
|
$name =~ s/^\*main::/*::/; |
1018
|
|
|
|
|
|
|
} else { |
1019
|
0
|
|
|
|
|
0
|
$name =~ s/^\*($package\::.+)/'*{' . $self->stringify($1) . '}'/e; |
|
0
|
|
|
|
|
0
|
|
1020
|
|
|
|
|
|
|
} |
1021
|
4
|
|
|
|
|
15
|
return $name; |
1022
|
|
|
|
|
|
|
} |
1023
|
|
|
|
|
|
|
|
1024
|
|
|
|
|
|
|
|
1025
|
|
|
|
|
|
|
|
1026
|
|
|
|
|
|
|
sub beautify { |
1027
|
0
|
|
|
0
|
1
|
0
|
my $self = &self; |
1028
|
0
|
|
|
|
|
0
|
my ( $method, @params ) = @_; |
1029
|
|
|
|
|
|
|
|
1030
|
0
|
|
0
|
|
|
0
|
$method = $self->can($method) || die "Cannot $method"; |
1031
|
|
|
|
|
|
|
|
1032
|
0
|
0
|
|
|
|
0
|
if ( my $beauty = $self->get('beautify') ) { |
1033
|
0
|
|
|
|
|
0
|
return $beauty->( $self->$method(@params) ); |
1034
|
|
|
|
|
|
|
} else { |
1035
|
0
|
|
|
|
|
0
|
return $self->$method(@params); |
1036
|
|
|
|
|
|
|
} |
1037
|
|
|
|
|
|
|
} |
1038
|
|
|
|
|
|
|
|
1039
|
|
|
|
|
|
|
### Private Methods & Settings ### |
1040
|
|
|
|
|
|
|
### Do not use these methods & settings outside of this package, |
1041
|
|
|
|
|
|
|
### they are subject to change or disappear at any time. |
1042
|
|
|
|
|
|
|
sub class { |
1043
|
11
|
100
|
|
11
|
0
|
8970
|
return scalar caller unless @_; |
1044
|
10
|
|
|
|
|
19
|
my $caller = caller; |
1045
|
10
|
|
|
|
|
13
|
my $class; |
1046
|
10
|
50
|
33
|
|
|
55
|
if ( defined( $class = Scalar::Util::blessed( $_[0] ) ) |
|
|
|
66
|
|
|
|
|
1047
|
|
|
|
|
|
|
|| ( !ref( $_[0] ) && length( $class = $_[0] ) ) ) |
1048
|
|
|
|
|
|
|
{ |
1049
|
10
|
100
|
|
|
|
42
|
if ( $class->isa($caller) ) { |
1050
|
8
|
|
|
|
|
13
|
shift; |
1051
|
8
|
|
|
|
|
20
|
return $class; |
1052
|
|
|
|
|
|
|
} |
1053
|
|
|
|
|
|
|
} |
1054
|
2
|
|
|
|
|
6
|
return $caller; |
1055
|
|
|
|
|
|
|
} |
1056
|
|
|
|
|
|
|
sub self { |
1057
|
7851
|
|
|
7851
|
0
|
9828
|
my $self = shift; |
1058
|
7851
|
100
|
|
|
|
18072
|
return defined( Scalar::Util::blessed($self) ) ? $self : $self->new(); |
1059
|
|
|
|
|
|
|
} |
1060
|
9621
|
|
100
|
9621
|
|
33865
|
sub _internal { return $_[0]->isa( scalar caller( 1 + ( $_[1] // 0 ) ) ) } |
1061
|
|
|
|
|
|
|
sub _private { |
1062
|
6628
|
100
|
|
6628
|
|
8650
|
Carp::croak('Illegal use of private method') unless $_[0]->_internal(1); |
1063
|
|
|
|
|
|
|
} |
1064
|
|
|
|
|
|
|
sub _settings() { |
1065
|
6628
|
|
|
6628
|
|
9965
|
&_private; |
1066
|
6627
|
|
|
|
|
9449
|
\state %SETTINGS; |
1067
|
|
|
|
|
|
|
} |
1068
|
|
|
|
|
|
|
|
1069
|
|
|
|
|
|
|
sub _nameify { |
1070
|
44
|
50
|
|
44
|
|
79
|
local $_ = shift if @_; |
1071
|
44
|
|
|
|
|
125
|
s/::/_/g; |
1072
|
44
|
|
|
|
|
250
|
return lc() . 'ify'; |
1073
|
|
|
|
|
|
|
} |
1074
|
|
|
|
|
|
|
sub _find_handler { |
1075
|
32
|
|
|
32
|
|
42
|
my $self = shift; |
1076
|
32
|
|
|
|
|
40
|
my $class = shift; |
1077
|
|
|
|
|
|
|
|
1078
|
32
|
|
|
|
|
110
|
my $isa = mro::get_linear_isa($class); |
1079
|
32
|
|
|
|
|
64
|
foreach my $c (@$isa) { |
1080
|
44
|
50
|
|
|
|
65
|
next unless my $code = $self->can( _nameify($c) ); |
1081
|
0
|
|
|
|
|
0
|
return $code; |
1082
|
|
|
|
|
|
|
} |
1083
|
32
|
|
|
|
|
101
|
return; |
1084
|
|
|
|
|
|
|
} |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
sub _subst { |
1087
|
535
|
50
|
|
535
|
|
1045
|
die "Cannot subst on an undefined value" |
1088
|
|
|
|
|
|
|
unless defined $_[0]; |
1089
|
535
|
|
|
|
|
1488
|
goto &String::Tools::subst; |
1090
|
|
|
|
|
|
|
} |
1091
|
|
|
|
|
|
|
|
1092
|
|
|
|
|
|
|
sub _get_delim { |
1093
|
464
|
|
|
464
|
|
566
|
my $self = shift; |
1094
|
464
|
|
|
|
|
518
|
my $open = shift; |
1095
|
|
|
|
|
|
|
|
1096
|
464
|
|
|
|
|
461
|
my $close; |
1097
|
464
|
50
|
|
|
|
801
|
if ( 1 < length $open ) { |
1098
|
0
|
|
0
|
|
|
0
|
my $qpairs = $self->get('qpairs') || []; |
1099
|
0
|
|
|
|
|
0
|
my %qpairs = map { $_ => 1 } @$qpairs; |
|
0
|
|
|
|
|
0
|
|
1100
|
0
|
0
|
|
|
|
0
|
if ( $qpairs{$open} ) { |
1101
|
0
|
|
|
|
|
0
|
( $open, $close ) = split //, $open, 2; |
1102
|
|
|
|
|
|
|
} else { |
1103
|
0
|
|
|
|
|
0
|
( $open ) = split //, $open, 1 |
1104
|
|
|
|
|
|
|
} |
1105
|
|
|
|
|
|
|
} |
1106
|
464
|
50
|
|
|
|
739
|
$close = $open unless $close; |
1107
|
|
|
|
|
|
|
|
1108
|
464
|
|
|
|
|
947
|
return $open, $close; |
1109
|
|
|
|
|
|
|
} |
1110
|
|
|
|
|
|
|
|
1111
|
|
|
|
|
|
|
sub _to_encode { |
1112
|
464
|
|
|
464
|
|
557
|
my $self = shift; |
1113
|
|
|
|
|
|
|
|
1114
|
464
|
|
|
|
|
659
|
my $encode = $self->get('encode'); |
1115
|
|
|
|
|
|
|
|
1116
|
|
|
|
|
|
|
# Ignore the settings for byte, byte2, byte3, byte4, vwide, wide, |
1117
|
|
|
|
|
|
|
# and utf |
1118
|
|
|
|
|
|
|
my @encode |
1119
|
464
|
|
|
|
|
1034
|
= grep { !(/\A(?:also|byte[234]?|v?wide|utf)\z/) } keys(%$encode); |
|
1665
|
|
|
|
|
4251
|
|
1120
|
|
|
|
|
|
|
|
1121
|
464
|
|
100
|
|
|
1287
|
my @ranges = ( $encode->{also} // () ); |
1122
|
464
|
|
|
|
|
809
|
foreach my $element (@_) { |
1123
|
1048
|
50
|
|
|
|
1897
|
if ( LooksLike::number($element) ) { |
|
|
50
|
|
|
|
|
|
1124
|
0
|
|
|
|
|
0
|
push @encode, $element; |
1125
|
|
|
|
|
|
|
} elsif ( length($element) == 1 ) { |
1126
|
|
|
|
|
|
|
# An actual character, lets get the ordinal value and use that |
1127
|
1048
|
|
|
|
|
16180
|
push @encode, ord($element); |
1128
|
|
|
|
|
|
|
} else { |
1129
|
|
|
|
|
|
|
# Something longer, it must be a range of chars, |
1130
|
|
|
|
|
|
|
# like [:cntrl:], \x00-\x7f, or similar |
1131
|
0
|
|
|
|
|
0
|
push @ranges, $element; |
1132
|
|
|
|
|
|
|
} |
1133
|
|
|
|
|
|
|
} |
1134
|
|
|
|
|
|
|
@encode = map { |
1135
|
|
|
|
|
|
|
# Encode characters in their \xXX or \x{XXXX} notation, |
1136
|
|
|
|
|
|
|
# to get the literal values |
1137
|
2079
|
100
|
|
|
|
5201
|
sprintf( $_ <= 255 ? '\\x%02x' : '\\x{%04x}', $_ ) |
1138
|
|
|
|
|
|
|
} sort { |
1139
|
464
|
|
|
|
|
1292
|
$a <=> $b |
|
3614
|
|
|
|
|
4624
|
|
1140
|
|
|
|
|
|
|
} @encode; |
1141
|
|
|
|
|
|
|
|
1142
|
464
|
|
|
|
|
1312
|
return join( '', @encode, @ranges ); |
1143
|
|
|
|
|
|
|
} |
1144
|
|
|
|
|
|
|
|
1145
|
|
|
|
|
|
|
sub _encode_ord2utf16 { |
1146
|
6
|
|
|
6
|
|
11
|
my $self = shift; |
1147
|
6
|
|
|
|
|
9
|
my $ord = shift; |
1148
|
|
|
|
|
|
|
|
1149
|
6
|
|
|
|
|
13
|
my $encode = $self->get('encode'); |
1150
|
6
|
|
|
|
|
11
|
my $format = $encode->{wide}; |
1151
|
6
|
|
|
|
|
10
|
my @wides = (); |
1152
|
6
|
100
|
33
|
|
|
27
|
if (0) { |
|
|
50
|
|
|
|
|
|
1153
|
0
|
50
|
|
|
|
0
|
} elsif ( 0x0000 <= $ord && $ord <= 0xffff ) { |
1154
|
5
|
50
|
33
|
|
|
14
|
if ( 0xd800 <= $ord && $ord <= 0xdfff ) { |
1155
|
0
|
|
|
|
|
0
|
die "Illegal character $ord"; |
1156
|
|
|
|
|
|
|
} |
1157
|
|
|
|
|
|
|
|
1158
|
5
|
|
|
|
|
13
|
@wides = ( $ord ); |
1159
|
|
|
|
|
|
|
} elsif ( 0x01_0000 <= $ord && $ord <= 0x10_ffff ) { |
1160
|
1
|
|
33
|
|
|
4
|
$format = $encode->{vwide} || $format x 2; |
1161
|
|
|
|
|
|
|
|
1162
|
1
|
|
|
|
|
3
|
$ord -= 0x01_0000; |
1163
|
1
|
|
|
|
|
2
|
my $ord2 = 0xdc00 + ( 0x3ff & $ord ); |
1164
|
1
|
|
|
|
|
3
|
$ord >>= 10; |
1165
|
1
|
|
|
|
|
4
|
my $ord1 = 0xd800 + ( 0x3ff & $ord ); |
1166
|
1
|
|
|
|
|
3
|
@wides = ( $ord1, $ord2 ); |
1167
|
|
|
|
|
|
|
} else { |
1168
|
0
|
|
|
|
|
0
|
die "Illegal character $ord"; |
1169
|
|
|
|
|
|
|
} |
1170
|
6
|
|
|
|
|
34
|
return sprintf( $format, @wides ); |
1171
|
|
|
|
|
|
|
} |
1172
|
|
|
|
|
|
|
sub _encode_ord2utf8 { |
1173
|
6
|
|
|
6
|
|
11
|
my $self = shift; |
1174
|
6
|
|
|
|
|
10
|
my $ord = shift; |
1175
|
|
|
|
|
|
|
|
1176
|
6
|
|
|
|
|
8
|
my @bytes = (); |
1177
|
6
|
|
|
|
|
12
|
my $format = undef; |
1178
|
|
|
|
|
|
|
|
1179
|
6
|
|
|
|
|
8
|
my $encode = $self->get('encode'); |
1180
|
6
|
50
|
66
|
|
|
56
|
if (0) { |
|
|
100
|
66
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1181
|
0
|
50
|
|
|
|
0
|
} elsif ( 0x00 <= $ord && $ord <= 0x7f ) { |
1182
|
|
|
|
|
|
|
# 1 byte represenstation |
1183
|
0
|
|
|
|
|
0
|
$format = $encode->{byte}; |
1184
|
0
|
|
|
|
|
0
|
@bytes = ( $ord ); |
1185
|
|
|
|
|
|
|
} elsif ( 0x0080 <= $ord && $ord <= 0x07ff ) { |
1186
|
|
|
|
|
|
|
# 2 byte represenstation |
1187
|
4
|
|
33
|
|
|
13
|
$format = $encode->{byte2} || $format x 2; |
1188
|
|
|
|
|
|
|
|
1189
|
4
|
|
|
|
|
8
|
my $ord2 = 0x80 + ( 0x3f & $ord ); |
1190
|
4
|
|
|
|
|
6
|
$ord >>= 6; |
1191
|
4
|
|
|
|
|
7
|
my $ord1 = 0xc0 + ( 0x1f & $ord ); |
1192
|
4
|
|
|
|
|
11
|
@bytes = ( $ord1, $ord2 ); |
1193
|
|
|
|
|
|
|
} elsif ( 0x0800 <= $ord && $ord <= 0xffff ) { |
1194
|
1
|
50
|
33
|
|
|
6
|
if ( 0xd800 <= $ord && $ord <= 0xdfff ) { |
1195
|
0
|
|
|
|
|
0
|
die "Illegal character $ord"; |
1196
|
|
|
|
|
|
|
} |
1197
|
|
|
|
|
|
|
|
1198
|
|
|
|
|
|
|
# 3 byte represenstation |
1199
|
1
|
|
33
|
|
|
5
|
$format = $encode->{byte3} || $format x 3; |
1200
|
|
|
|
|
|
|
|
1201
|
1
|
|
|
|
|
4
|
my $ord3 = 0x80 + ( 0x3f & $ord ); |
1202
|
1
|
|
|
|
|
3
|
$ord >>= 6; |
1203
|
1
|
|
|
|
|
2
|
my $ord2 = 0x80 + ( 0x3f & $ord ); |
1204
|
1
|
|
|
|
|
3
|
$ord >>= 6; |
1205
|
1
|
|
|
|
|
3
|
my $ord1 = 0xe0 + ( 0x0f & $ord ); |
1206
|
1
|
|
|
|
|
3
|
@bytes = ( $ord1, $ord2, $ord3 ); |
1207
|
|
|
|
|
|
|
} elsif ( 0x01_0000 <= $ord && $ord <= 0x10_ffff ) { |
1208
|
|
|
|
|
|
|
# 4 byte represenstation |
1209
|
1
|
|
33
|
|
|
4
|
$format = $encode->{byte4} || $format x 4; |
1210
|
|
|
|
|
|
|
|
1211
|
1
|
|
|
|
|
4
|
my $ord4 = 0x80 + ( 0x3f & $ord ); |
1212
|
1
|
|
|
|
|
2
|
$ord >>= 6; |
1213
|
1
|
|
|
|
|
5
|
my $ord3 = 0x80 + ( 0x3f & $ord ); |
1214
|
1
|
|
|
|
|
3
|
$ord >>= 6; |
1215
|
1
|
|
|
|
|
2
|
my $ord2 = 0x80 + ( 0x3f & $ord ); |
1216
|
1
|
|
|
|
|
13
|
$ord >>= 6; |
1217
|
1
|
|
|
|
|
3
|
my $ord1 = 0xf0 + ( 0x07 & $ord ); |
1218
|
1
|
|
|
|
|
4
|
@bytes = ( $ord1, $ord2, $ord3, $ord4 ); |
1219
|
|
|
|
|
|
|
} else { |
1220
|
0
|
|
|
|
|
0
|
die "Illegal character $ord"; |
1221
|
|
|
|
|
|
|
} |
1222
|
6
|
|
|
|
|
36
|
return sprintf( $format, @bytes ); |
1223
|
|
|
|
|
|
|
} |
1224
|
|
|
|
|
|
|
sub _encode_char { |
1225
|
295
|
|
|
295
|
|
395
|
my $self = shift; |
1226
|
295
|
|
|
|
|
517
|
my $ord = ord shift; |
1227
|
|
|
|
|
|
|
|
1228
|
295
|
|
|
|
|
456
|
my $encode = $self->get('encode'); |
1229
|
295
|
|
100
|
|
|
741
|
my $utf = $encode->{utf} // 0; |
1230
|
295
|
100
|
|
|
|
679
|
if ( defined $encode->{$ord} ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1231
|
153
|
|
|
|
|
488
|
return $encode->{$ord}; |
1232
|
|
|
|
|
|
|
} elsif ( $utf == 8 ) { |
1233
|
6
|
|
|
|
|
15
|
return $self->_encode_ord2utf8( $ord ); |
1234
|
|
|
|
|
|
|
} elsif ( $utf == 16 ) { |
1235
|
6
|
|
|
|
|
18
|
return $self->_encode_ord2utf16( $ord ); |
1236
|
|
|
|
|
|
|
} elsif ( $ord <= 255 ) { |
1237
|
127
|
|
|
|
|
584
|
return sprintf $encode->{byte}, $ord; |
1238
|
|
|
|
|
|
|
} elsif ( $ord <= 65_535 ) { |
1239
|
2
|
|
33
|
|
|
7
|
my $encoding = $encode->{wide} // $encode->{byte}; |
1240
|
2
|
|
|
|
|
12
|
return sprintf $encoding, $ord; |
1241
|
|
|
|
|
|
|
} else { |
1242
|
1
|
|
33
|
|
|
8
|
my $encoding = $encode->{vwide} // $encode->{wide} // $encode->{byte}; |
|
|
|
0
|
|
|
|
|
1243
|
1
|
|
|
|
|
5
|
return sprintf $encoding, $ord; |
1244
|
|
|
|
|
|
|
} |
1245
|
|
|
|
|
|
|
} |
1246
|
|
|
|
|
|
|
|
1247
|
|
|
|
|
|
|
# Find a good character to use for delimiting q or qq. |
1248
|
|
|
|
|
|
|
sub _find_q { |
1249
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
1250
|
1
|
50
|
|
|
|
4
|
local $_ = shift if @_; |
1251
|
|
|
|
|
|
|
|
1252
|
1
|
|
|
|
|
2
|
my %counts; |
1253
|
1
|
|
|
|
|
168
|
$counts{$_}++ foreach /([[:punct:]])/g; |
1254
|
|
|
|
|
|
|
#$counts{$_}++ foreach grep /[[:punct:]]/, split //; |
1255
|
1
|
|
50
|
|
|
14
|
my $qpairs = $self->get('qpairs') || []; |
1256
|
1
|
|
|
|
|
2
|
foreach my $pair (@$qpairs) { |
1257
|
|
|
|
|
|
|
$counts{$pair} |
1258
|
|
|
|
|
|
|
= List::Util::sum 0, |
1259
|
|
|
|
|
|
|
grep defined, |
1260
|
4
|
|
|
|
|
11
|
map { $counts{$_} } |
|
8
|
|
|
|
|
22
|
|
1261
|
|
|
|
|
|
|
split //, $pair; |
1262
|
|
|
|
|
|
|
} |
1263
|
|
|
|
|
|
|
|
1264
|
|
|
|
|
|
|
return List::Util::reduce { |
1265
|
23
|
100
|
50
|
23
|
|
60
|
( ( $counts{$a} //= 0 ) <= ( $counts{$b} //= 0 ) ) ? $a : $b |
|
|
|
50
|
|
|
|
|
1266
|
1
|
|
|
|
|
5
|
} @{ $self->get('qpairs') }, @{ $self->get('qquotes') }; |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
3
|
|
1267
|
|
|
|
|
|
|
} |
1268
|
|
|
|
|
|
|
sub _push_position { |
1269
|
596
|
|
|
596
|
|
755
|
my $self = shift; |
1270
|
596
|
|
|
|
|
688
|
my $position = shift; |
1271
|
596
|
|
50
|
|
|
627
|
push @{ $self->{_position} //= [] }, $position; |
|
596
|
|
|
|
|
1295
|
|
1272
|
596
|
|
|
|
|
829
|
return $self; |
1273
|
|
|
|
|
|
|
} |
1274
|
|
|
|
|
|
|
sub _pop_position { |
1275
|
594
|
|
|
594
|
|
670
|
my $self = shift; |
1276
|
594
|
|
|
|
|
580
|
return pop @{ $self->{_position} }; |
|
594
|
|
|
|
|
1325
|
|
1277
|
|
|
|
|
|
|
} |
1278
|
|
|
|
|
|
|
sub _cache_position { |
1279
|
142
|
|
|
142
|
|
171
|
my $self = shift; |
1280
|
|
|
|
|
|
|
|
1281
|
142
|
|
33
|
|
|
229
|
my $nest = $self->get('nested') // $self->get('dereference'); |
1282
|
|
|
|
|
|
|
my $pos = List::Util::reduce( |
1283
|
0
|
|
|
0
|
|
0
|
sub { _subst( $nest, referent => $a, place => $b ) }, |
1284
|
142
|
|
100
|
|
|
520
|
@{ $self->{_position} //= [] } |
|
142
|
|
|
|
|
647
|
|
1285
|
|
|
|
|
|
|
); |
1286
|
|
|
|
|
|
|
|
1287
|
142
|
|
|
|
|
464
|
my $var = $self->get('name'); |
1288
|
142
|
50
|
|
|
|
383
|
my $sigil = length $var ? substr $var, 0, 1 : ''; |
1289
|
142
|
50
|
33
|
|
|
550
|
if ( $sigil eq '@' || $sigil eq '%' ) { |
|
|
100
|
|
|
|
|
|
1290
|
0
|
0
|
|
|
|
0
|
if ($pos) { |
1291
|
0
|
|
|
|
|
0
|
$var = sprintf '$%s%s', substr($var, 1), $pos; |
1292
|
|
|
|
|
|
|
} else { |
1293
|
0
|
|
|
|
|
0
|
$var = _subst( $self->get('reference'), $var ); |
1294
|
|
|
|
|
|
|
} |
1295
|
|
|
|
|
|
|
} elsif ($pos) { |
1296
|
32
|
|
33
|
|
|
79
|
$var = _subst( |
1297
|
|
|
|
|
|
|
$self->get('dereference') // $self->get('nested'), |
1298
|
|
|
|
|
|
|
referent => $var, |
1299
|
|
|
|
|
|
|
place => $pos |
1300
|
|
|
|
|
|
|
); |
1301
|
|
|
|
|
|
|
} |
1302
|
142
|
|
|
|
|
3151
|
return $var; |
1303
|
|
|
|
|
|
|
} |
1304
|
|
|
|
|
|
|
|
1305
|
|
|
|
|
|
|
__PACKAGE__->set( |
1306
|
|
|
|
|
|
|
# _caching options |
1307
|
|
|
|
|
|
|
_cache_hit => 0, |
1308
|
|
|
|
|
|
|
); |
1309
|
|
|
|
|
|
|
sub _cache_add { |
1310
|
511
|
|
|
511
|
|
659
|
my $self = shift; |
1311
|
511
|
|
|
|
|
583
|
my $ref = shift; |
1312
|
511
|
|
|
|
|
552
|
my $value = shift; |
1313
|
|
|
|
|
|
|
|
1314
|
511
|
100
|
|
|
|
1181
|
return $self unless my $refaddr = Scalar::Util::refaddr $ref; |
1315
|
110
|
|
50
|
|
|
238
|
my $_cache = $self->{_cache} //= {}; |
1316
|
110
|
|
50
|
|
|
205
|
my $entry = $_cache->{$refaddr} //= [ $self->_cache_position ]; |
1317
|
110
|
50
|
|
|
|
210
|
push @$entry, $value if @$entry == $self->get('_cache_hit'); |
1318
|
|
|
|
|
|
|
|
1319
|
110
|
|
|
|
|
167
|
return $self; |
1320
|
|
|
|
|
|
|
} |
1321
|
|
|
|
|
|
|
sub _cache_get { |
1322
|
552
|
|
|
552
|
|
650
|
my $self = shift; |
1323
|
552
|
|
|
|
|
659
|
my $item = shift; |
1324
|
|
|
|
|
|
|
|
1325
|
552
|
100
|
|
|
|
1588
|
return unless my $refaddr = Scalar::Util::refaddr $item; |
1326
|
|
|
|
|
|
|
|
1327
|
148
|
|
100
|
|
|
401
|
my $_cache = $self->{_cache} //= {}; |
1328
|
148
|
100
|
|
|
|
309
|
if ( my $entry = $_cache->{$refaddr} ) { |
1329
|
6
|
|
|
|
|
22
|
my $repr = $self->get('_cache_hit'); |
1330
|
6
|
|
33
|
|
|
32
|
return $entry->[$repr] |
1331
|
|
|
|
|
|
|
// Carp::croak 'Recursive structures not allowed at ', |
1332
|
|
|
|
|
|
|
$self->_cache_position; |
1333
|
|
|
|
|
|
|
} else { |
1334
|
|
|
|
|
|
|
# Pre-populate the cache, so that we can check for loops |
1335
|
142
|
|
|
|
|
283
|
$_cache->{$refaddr} = [ $self->_cache_position ]; |
1336
|
142
|
|
|
|
|
453
|
return; |
1337
|
|
|
|
|
|
|
} |
1338
|
|
|
|
|
|
|
} |
1339
|
|
|
|
|
|
|
sub _cache_reset { |
1340
|
41
|
|
|
41
|
|
63
|
my $self = shift; |
1341
|
41
|
|
100
|
|
|
60
|
%{ $self->{_cache} //= {} } = (); |
|
41
|
|
|
|
|
151
|
|
1342
|
41
|
|
|
|
|
55
|
return $self; |
1343
|
|
|
|
|
|
|
} |
1344
|
|
|
|
|
|
|
|
1345
|
|
|
|
|
|
|
1; |
1346
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
__END__ |