line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
5
|
|
|
5
|
|
253625
|
use v5.14; |
|
5
|
|
|
|
|
20
|
|
2
|
5
|
|
|
5
|
|
28
|
use warnings; |
|
5
|
|
|
|
|
8
|
|
|
5
|
|
|
|
|
210
|
|
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
package Datify v0.20.052; |
5
|
|
|
|
|
|
|
# ABSTRACT: Simple stringification of data. |
6
|
|
|
|
|
|
|
|
7
|
|
|
|
|
|
|
|
8
|
5
|
|
|
5
|
|
32
|
use mro (); #qw( get_linear_isa ); |
|
5
|
|
|
|
|
18
|
|
|
5
|
|
|
|
|
79
|
|
9
|
5
|
|
|
5
|
|
24
|
use overload (); #qw( Method Overloaded ); |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
83
|
|
10
|
|
|
|
|
|
|
|
11
|
5
|
|
|
5
|
|
23
|
use Carp (); #qw( carp croak ); |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
101
|
|
12
|
5
|
|
|
5
|
|
25
|
use List::Util (); #qw( reduce sum ); |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
79
|
|
13
|
5
|
|
|
5
|
|
2535
|
use LooksLike (); #qw( numeric ); |
|
5
|
|
|
|
|
18198
|
|
|
5
|
|
|
|
|
163
|
|
14
|
5
|
|
|
5
|
|
38
|
use Scalar::Util (); #qw( blessed looks_like_number refaddr reftype ); |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
124
|
|
15
|
5
|
|
|
5
|
|
2577
|
use String::Tools v0.18.277 (); #qw( stitch stringify subst ); |
|
5
|
|
|
|
|
7756
|
|
|
5
|
|
|
|
|
149
|
|
16
|
5
|
|
|
5
|
|
2380
|
use Sub::Util 1.40 (); #qw( subname ); |
|
5
|
|
|
|
|
1573
|
|
|
5
|
|
|
|
|
3723
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
### Constructor ### |
20
|
|
|
|
|
|
|
|
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
sub new { |
23
|
2817
|
|
50
|
2817
|
1
|
15380
|
my $class = shift || __PACKAGE__; |
24
|
|
|
|
|
|
|
|
25
|
2817
|
|
|
|
|
3805
|
my %self = (); |
26
|
2817
|
50
|
|
|
|
5541
|
if ( defined( my $blessed = Scalar::Util::blessed($class) ) ) { |
27
|
0
|
|
|
|
|
0
|
%self = %$class; # shallow copy |
28
|
0
|
|
|
|
|
0
|
$class = $blessed; |
29
|
|
|
|
|
|
|
} |
30
|
2817
|
100
|
|
|
|
7094
|
return @_ ? bless( \%self, $class )->set(@_) : bless( \%self, $class ); |
31
|
|
|
|
|
|
|
} |
32
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
|
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
### Accessor ### |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub exists { |
41
|
7281
|
|
|
7281
|
1
|
9082
|
my $self = shift; |
42
|
7281
|
50
|
|
|
|
12338
|
return unless my $count = scalar(@_); |
43
|
|
|
|
|
|
|
|
44
|
7281
|
|
|
|
|
11015
|
my $SETTINGS = $self->_settings; |
45
|
7281
|
100
|
|
|
|
16576
|
if ( Scalar::Util::blessed($self) ) { |
46
|
|
|
|
|
|
|
return $count == 1 |
47
|
|
|
|
|
|
|
? exists $self->{ $_[0] } && $self |
48
|
|
|
|
|
|
|
|| exists $SETTINGS->{ $_[0] } && $SETTINGS |
49
|
|
|
|
|
|
|
: map { |
50
|
7237
|
50
|
100
|
|
|
36197
|
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
|
|
|
516
|
: map { exists $SETTINGS->{ $_ } && $SETTINGS } @_; |
|
0
|
50
|
|
|
|
0
|
|
57
|
|
|
|
|
|
|
} |
58
|
|
|
|
|
|
|
} |
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
sub _get_setting { |
63
|
7243
|
|
|
7243
|
|
13628
|
my $setting = $_[0]->exists( local $_ = $_[1] ); |
64
|
7243
|
100
|
|
|
|
23070
|
return $setting ? $setting->{$_} : do { |
65
|
689
|
50
|
|
|
|
1283
|
Carp::carp( 'Unknown key ', $_ ) |
66
|
|
|
|
|
|
|
unless $_[0]->_internal(1); |
67
|
|
|
|
|
|
|
undef |
68
|
689
|
|
|
|
|
1694
|
}; |
69
|
|
|
|
|
|
|
} |
70
|
|
|
|
|
|
|
sub get { |
71
|
6375
|
|
|
6375
|
1
|
13984
|
my $self = shift; |
72
|
6375
|
|
|
|
|
8672
|
my $count = scalar(@_); |
73
|
|
|
|
|
|
|
|
74
|
6375
|
100
|
|
|
|
16368
|
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
|
6368
|
100
|
|
|
|
15089
|
: map { $self->_get_setting($_) } @_; |
|
1316
|
50
|
|
|
|
2172
|
|
79
|
|
|
|
|
|
|
} else { |
80
|
|
|
|
|
|
|
return |
81
|
1
|
|
|
|
|
2
|
$count == 0 ? %{ $self->_settings } |
82
|
|
|
|
|
|
|
: $count == 1 ? $self->_get_setting(shift) |
83
|
7
|
50
|
|
|
|
26
|
: map { $self->_get_setting($_) } @_; |
|
0
|
100
|
|
|
|
0
|
|
84
|
|
|
|
|
|
|
} |
85
|
|
|
|
|
|
|
} |
86
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
### Setter ### |
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
sub set { |
92
|
1238
|
|
|
1238
|
1
|
10012
|
my $self = shift; |
93
|
1238
|
50
|
|
|
|
2390
|
return $self unless @_; |
94
|
1238
|
|
|
|
|
3006
|
my %set = @_; |
95
|
|
|
|
|
|
|
|
96
|
1238
|
|
|
|
|
1703
|
my $return; |
97
|
|
|
|
|
|
|
my $class; |
98
|
1238
|
100
|
|
|
|
3339
|
if ( defined( $class = Scalar::Util::blessed($self) ) ) { |
99
|
|
|
|
|
|
|
# Make a shallow copy |
100
|
1111
|
|
|
|
|
4539
|
$self = bless { %$self }, $class; |
101
|
1111
|
|
|
|
|
1936
|
$return = 0; |
102
|
|
|
|
|
|
|
} else { |
103
|
127
|
|
|
|
|
179
|
$class = $self; |
104
|
127
|
|
|
|
|
217
|
$self = $class->_settings; |
105
|
127
|
|
|
|
|
168
|
$return = 1; |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
1238
|
100
|
|
|
|
2803
|
delete $self->{keyword_set} if ( $set{keywords} ); |
109
|
1238
|
|
|
|
|
2108
|
delete $self->{"_tr$_"} for grep { exists $set{"quote$_"} } ( 1, 2, 3 ); |
|
3714
|
|
|
|
|
8146
|
|
110
|
|
|
|
|
|
|
|
111
|
1238
|
|
|
|
|
2535
|
my $internal = $class->_internal; |
112
|
1238
|
|
|
|
|
3946
|
while ( my ( $k, $v ) = each %set ) { |
113
|
1435
|
100
|
100
|
|
|
2971
|
Carp::carp( 'Unknown key ', $k ) |
114
|
|
|
|
|
|
|
unless $internal || $class->exists($k); |
115
|
1435
|
100
|
100
|
|
|
4396
|
study($v) if defined($v) && !ref($v); |
116
|
1435
|
|
|
|
|
4572
|
$self->{$k} = $v; |
117
|
|
|
|
|
|
|
} |
118
|
|
|
|
|
|
|
|
119
|
1238
|
|
|
|
|
3240
|
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
|
|
44
|
no strict 'refs'; |
|
5
|
|
|
|
|
9
|
|
|
5
|
|
|
|
|
6506
|
|
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
|
17561
|
my $self = &self; |
172
|
41
|
|
|
|
|
80
|
my ($sigil, $name); |
173
|
41
|
50
|
33
|
|
|
173
|
if ( defined $_[0] && !ref $_[0] ) { |
174
|
41
|
|
|
|
|
770
|
( $sigil, $name ) |
175
|
|
|
|
|
|
|
= $_[0] =~ /^($sigils)?((?:$package\::)?$varname|$package\::)$/; |
176
|
41
|
50
|
|
|
|
148
|
shift if length $name; |
177
|
|
|
|
|
|
|
} |
178
|
41
|
50
|
|
|
|
108
|
my $value = 1 == @_ ? shift : \@_; |
179
|
|
|
|
|
|
|
|
180
|
41
|
50
|
|
|
|
76
|
if ( length $name ) { |
181
|
41
|
50
|
|
|
|
118
|
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
|
|
|
|
104
|
Carp::croak "Missing name" unless ( length $name ); |
193
|
|
|
|
|
|
|
|
194
|
41
|
100
|
|
|
|
84
|
unless ($sigil) { |
195
|
22
|
|
|
|
|
47
|
my $ref = ref $value; |
196
|
22
|
50
|
|
|
|
76
|
$sigil |
|
|
50
|
|
|
|
|
|
197
|
|
|
|
|
|
|
= $ref eq 'ARRAY' ? '@' |
198
|
|
|
|
|
|
|
: $ref eq 'HASH' ? '%' |
199
|
|
|
|
|
|
|
: '$'; |
200
|
|
|
|
|
|
|
} |
201
|
41
|
|
|
|
|
79
|
$name = $sigil . $name; |
202
|
41
|
|
|
|
|
141
|
$self = $self->set( name => $name ); |
203
|
|
|
|
|
|
|
|
204
|
41
|
0
|
|
|
|
151
|
$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
|
|
|
|
|
88
|
$value = _subst( $self->get('assign'), var => $name, value => $value ); |
212
|
41
|
50
|
|
|
|
3826
|
if ( my $beautify = $self->get('beautify') ) { |
213
|
0
|
|
|
|
|
0
|
return $beautify->($value); |
214
|
|
|
|
|
|
|
} else { |
215
|
41
|
|
|
|
|
230
|
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
|
17
|
|
|
17
|
1
|
41
|
my $self = &self; |
232
|
17
|
50
|
33
|
|
|
66
|
return $self->scalarify(shift) if @_ and defined($_[0]); |
233
|
17
|
|
|
|
|
41
|
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
|
4549
|
my $self = &self; |
262
|
400
|
50
|
|
|
|
1078
|
local $_ = shift if @_; |
263
|
400
|
50
|
|
|
|
771
|
return $self->undefify unless defined; |
264
|
400
|
50
|
|
|
|
681
|
$_ = String::Tools::stringify($_) if ref; |
265
|
400
|
|
|
|
|
824
|
my $quote1 = $self->get('quote1'); |
266
|
400
|
|
66
|
|
|
1357
|
my ( $open, $close ) = $self->_get_delim( shift // $quote1 ); |
267
|
|
|
|
|
|
|
|
268
|
400
|
|
|
|
|
774
|
$self = $self->set( encode => $self->get('encode1') ); |
269
|
400
|
|
|
|
|
826
|
my $to_encode = $self->_to_encode( $open, $close ); |
270
|
400
|
|
|
|
|
1788
|
s/([$to_encode])/$self->_encode_char($1)/eg; |
|
116
|
|
|
|
|
296
|
|
271
|
|
|
|
|
|
|
|
272
|
400
|
100
|
|
|
|
1035
|
if ( $quote1 ne $open ) { |
273
|
1
|
50
|
|
|
|
5
|
if ( $open =~ /\w/ ) { |
274
|
0
|
|
|
|
|
0
|
$open = ' ' . $open; |
275
|
0
|
|
|
|
|
0
|
$close = ' ' . $close; |
276
|
|
|
|
|
|
|
} |
277
|
1
|
|
|
|
|
3
|
$open = $self->get('q1') . $open; |
278
|
|
|
|
|
|
|
} |
279
|
|
|
|
|
|
|
|
280
|
400
|
|
|
|
|
3214
|
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
|
4298
|
my $self = &self; |
290
|
60
|
50
|
|
|
|
168
|
local $_ = shift if @_; |
291
|
60
|
50
|
|
|
|
125
|
return $self->undefify unless defined; |
292
|
60
|
50
|
|
|
|
127
|
$_ = String::Tools::stringify($_) if ref; |
293
|
60
|
|
|
|
|
131
|
my $quote2 = $self->get('quote2'); |
294
|
60
|
|
33
|
|
|
238
|
my ( $open, $close ) = $self->_get_delim( shift // $quote2 ); |
295
|
|
|
|
|
|
|
|
296
|
60
|
|
|
|
|
100
|
my @sigils; |
297
|
60
|
50
|
|
|
|
122
|
if ( my $sigils = $self->get('sigils') ) { |
298
|
60
|
|
|
|
|
247
|
push @sigils, split //, $sigils; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
|
301
|
|
|
|
|
|
|
# quote char(s), sigils, and backslash. |
302
|
60
|
|
|
|
|
170
|
$self = $self->set( encode => $self->get('encode2') ); |
303
|
60
|
|
|
|
|
194
|
my $to_encode = $self->_to_encode( $open, $close, @sigils ); |
304
|
60
|
|
|
|
|
609
|
s/([$to_encode])/$self->_encode_char($1)/eg; |
|
179
|
|
|
|
|
403
|
|
305
|
|
|
|
|
|
|
|
306
|
60
|
50
|
|
|
|
184
|
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
|
|
|
|
|
464
|
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
|
|
|
|
|
10
|
|
|
5
|
|
|
|
|
11028
|
|
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
|
4786
|
my $self = &self; |
374
|
422
|
50
|
|
|
|
922
|
local $_ = shift if @_; |
375
|
422
|
50
|
|
|
|
744
|
return $self->undefify unless defined; |
376
|
422
|
50
|
|
|
|
716
|
$_ = String::Tools::stringify($_) if ref; |
377
|
422
|
|
|
|
|
641
|
local $@ = undef; |
378
|
|
|
|
|
|
|
|
379
|
422
|
|
|
|
|
805
|
my ( $quote, $quote1, $quote2 ) = $self->get(qw( quote quote1 quote2 )); |
380
|
422
|
50
|
|
|
|
960
|
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
|
|
|
|
|
814
|
my $longstr = $self->get('longstr'); |
388
|
422
|
|
|
|
|
870
|
my $encode2 = $self->get('encode2'); |
389
|
422
|
|
33
|
|
|
1246
|
my $also = $encode2 && $encode2->{also}; |
390
|
422
|
100
|
33
|
|
|
3288
|
return $self->stringify2($_) |
|
|
|
66
|
|
|
|
|
|
|
|
66
|
|
|
|
|
391
|
|
|
|
|
|
|
if ( ( $longstr && $longstr < length() ) || ( $also && /[$also]/ ) ); |
392
|
|
|
|
|
|
|
|
393
|
410
|
|
|
|
|
933
|
my $tr1 = $self->get('_tr1'); |
394
|
410
|
50
|
|
|
|
1443
|
$self = $self->set( _tr1 => $tr1 = "tr\\$quote1\\$quote1\\" ) |
395
|
|
|
|
|
|
|
if ( not $tr1 ); |
396
|
410
|
|
50
|
|
|
24293
|
my $single_quotes = eval $tr1 // die $@; |
397
|
410
|
100
|
|
|
|
1854
|
return $self->stringify1($_) unless $single_quotes; |
398
|
|
|
|
|
|
|
|
399
|
21
|
|
|
|
|
143
|
my ( $sigils, $tr2 ) = $self->get(qw( sigils _tr2 )); |
400
|
21
|
50
|
|
|
|
130
|
$self = $self->set( _tr2 => $tr2 = "tr\\$quote2$sigils\\$quote2$sigils\\" ) |
401
|
|
|
|
|
|
|
if ( not $tr2 ); |
402
|
21
|
|
50
|
|
|
1116
|
my $double_quotes = eval $tr2 // die $@; |
403
|
21
|
100
|
|
|
|
115
|
return $self->stringify2($_) unless $double_quotes; |
404
|
|
|
|
|
|
|
|
405
|
1
|
|
|
|
|
4
|
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
|
3322
|
|
|
3322
|
1
|
4909
|
my $self = &self; |
425
|
3322
|
50
|
|
|
|
6571
|
local $_ = shift if @_; |
426
|
|
|
|
|
|
|
|
427
|
3322
|
50
|
|
|
|
5362
|
return undef unless defined; |
428
|
|
|
|
|
|
|
|
429
|
3322
|
50
|
|
|
|
5083
|
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
|
3322
|
|
|
|
|
5865
|
return LooksLike::numeric($_); |
439
|
|
|
|
|
|
|
} |
440
|
|
|
|
|
|
|
|
441
|
|
|
|
|
|
|
|
442
|
|
|
|
|
|
|
sub numify { |
443
|
384
|
|
|
384
|
1
|
34422
|
my $self = &self; |
444
|
384
|
50
|
|
|
|
882
|
local $_ = shift if @_; |
445
|
|
|
|
|
|
|
|
446
|
384
|
100
|
|
|
|
716
|
return $self->undefify unless defined; |
447
|
|
|
|
|
|
|
|
448
|
383
|
100
|
|
|
|
686
|
if ( $self->is_numeric($_) ) { |
|
|
100
|
|
|
|
|
|
449
|
369
|
50
|
|
|
|
5060
|
return $_ unless my $sep = $self->get('num_sep'); |
450
|
|
|
|
|
|
|
|
451
|
|
|
|
|
|
|
# Fractional portion |
452
|
369
|
|
|
|
|
1129
|
s{^(\s*[-+]?\d*\.\d\d)(\d+)} [${1}$sep${2}]; |
453
|
369
|
|
|
|
|
1715
|
1 while s{^(\s*[-+]?\d*\.(?:\d+$sep)+\d\d\d)(\d+)}[${1}$sep${2}]; |
454
|
|
|
|
|
|
|
|
455
|
|
|
|
|
|
|
# Whole portion |
456
|
369
|
|
|
|
|
1426
|
1 while s{^(\s*[-+]?\d+)(\d{3})} [${1}$sep${2}]; |
457
|
|
|
|
|
|
|
|
458
|
369
|
|
|
|
|
1332
|
return $_; |
459
|
|
|
|
|
|
|
} |
460
|
|
|
|
|
|
|
elsif ( Scalar::Util::looks_like_number($_) ) { |
461
|
|
|
|
|
|
|
return |
462
|
12
|
50
|
|
|
|
204
|
$_ == 'inf' ? $self->get('infinite') |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
463
|
|
|
|
|
|
|
: $_ == '-inf' ? $self->get('-infinite') |
464
|
|
|
|
|
|
|
: defined( $_ <=> 0 ) ? $_ |
465
|
|
|
|
|
|
|
: $self->get('nonnumber'); |
466
|
|
|
|
|
|
|
} |
467
|
|
|
|
|
|
|
|
468
|
2
|
|
|
|
|
106
|
return $self->get('nonnumber'); |
469
|
|
|
|
|
|
|
} |
470
|
|
|
|
|
|
|
|
471
|
|
|
|
|
|
|
|
472
|
|
|
|
|
|
|
|
473
|
|
|
|
|
|
|
### Scalar ### |
474
|
|
|
|
|
|
|
|
475
|
|
|
|
|
|
|
|
476
|
|
|
|
|
|
|
__PACKAGE__->set( |
477
|
|
|
|
|
|
|
# Scalar options |
478
|
|
|
|
|
|
|
scalar_ref => '\do{1;$_}', |
479
|
|
|
|
|
|
|
); |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
|
482
|
|
|
|
|
|
|
sub scalarify { |
483
|
548
|
|
|
548
|
1
|
18690
|
my $self = &self; |
484
|
548
|
50
|
|
|
|
1403
|
local $_ = shift if @_; |
485
|
|
|
|
|
|
|
|
486
|
548
|
|
100
|
|
|
1004
|
my $value = $self->_cache_get($_) // $self->_scalarify($_); |
487
|
548
|
100
|
|
|
|
12839
|
$self->isa( scalar caller ) |
488
|
|
|
|
|
|
|
? $self->_cache_add( $_ => $value ) |
489
|
|
|
|
|
|
|
: $self->_cache_reset($_); |
490
|
548
|
|
|
|
|
1321
|
return $value; |
491
|
|
|
|
|
|
|
} |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
sub _scalarify { |
494
|
542
|
|
|
542
|
|
867
|
my $self = &self; |
495
|
542
|
50
|
|
|
|
1241
|
local $_ = shift if @_; |
496
|
|
|
|
|
|
|
|
497
|
542
|
100
|
|
|
|
1043
|
return $self->undefify unless defined $_; |
498
|
|
|
|
|
|
|
|
499
|
526
|
100
|
|
|
|
1284
|
if ( defined( my $blessed = Scalar::Util::blessed($_) ) ) { |
500
|
|
|
|
|
|
|
return |
501
|
36
|
100
|
|
|
|
101
|
$blessed eq 'Regexp' ? $self->regexpify($_) |
502
|
|
|
|
|
|
|
: $self->objectify($_); |
503
|
|
|
|
|
|
|
} |
504
|
|
|
|
|
|
|
|
505
|
490
|
|
|
|
|
870
|
my $ref = Scalar::Util::reftype $_; |
506
|
490
|
100
|
|
|
|
885
|
if ( not $ref ) { |
507
|
|
|
|
|
|
|
# Handle GLOB, LVALUE, and VSTRING |
508
|
384
|
|
|
|
|
730
|
my $ref2 = ref \$_; |
509
|
|
|
|
|
|
|
return |
510
|
384
|
100
|
|
|
|
1961
|
$ref2 eq 'GLOB' ? $self->globify($_) |
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
511
|
|
|
|
|
|
|
: $ref2 eq 'LVALUE' ? $self->lvalueify($_) |
512
|
|
|
|
|
|
|
: $ref2 eq 'VSTRING' ? $self->vstringify($_) |
513
|
|
|
|
|
|
|
: $ref2 eq 'SCALAR' ? ( |
514
|
|
|
|
|
|
|
Scalar::Util::looks_like_number($_) |
515
|
|
|
|
|
|
|
? $self->numify($_) |
516
|
|
|
|
|
|
|
: $self->stringify($_) |
517
|
|
|
|
|
|
|
) |
518
|
|
|
|
|
|
|
: $self->stringify($_); |
519
|
|
|
|
|
|
|
} |
520
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
return |
522
|
|
|
|
|
|
|
$ref eq 'ARRAY' ? $self->arrayify(@$_) |
523
|
|
|
|
|
|
|
: $ref eq 'CODE' ? $self->codeify($_) |
524
|
|
|
|
|
|
|
: $ref eq 'FORMAT' ? $self->formatify($_) |
525
|
|
|
|
|
|
|
: $ref eq 'HASH' ? $self->hashify($_) |
526
|
|
|
|
|
|
|
: $ref eq 'IO' ? $self->ioify($_) |
527
|
|
|
|
|
|
|
: $ref eq 'REF' ? $self->refify($$_) |
528
|
|
|
|
|
|
|
: $ref eq 'REGEXP' ? $self->regexpify($_) # ??? |
529
|
106
|
50
|
|
|
|
527
|
: do { |
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
530
|
18
|
|
33
|
|
|
59
|
my $reference = $self->get( lc($ref) . '_reference' ) |
531
|
|
|
|
|
|
|
|| $self->get('reference'); |
532
|
|
|
|
|
|
|
|
533
|
18
|
50
|
|
|
|
79
|
$ref eq 'GLOB' ? _subst( $reference, $self->globify($$_) ) |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
534
|
|
|
|
|
|
|
: $ref eq 'LVALUE' ? _subst( $reference, $self->lvalueify($$_) ) |
535
|
|
|
|
|
|
|
: $ref eq 'SCALAR' ? _subst( $reference, $self->scalarify($$_) ) |
536
|
|
|
|
|
|
|
: $ref eq 'VSTRING' ? _subst( $reference, $self->vstringify($$_) ) |
537
|
|
|
|
|
|
|
: $self->objectify($_) |
538
|
|
|
|
|
|
|
; |
539
|
|
|
|
|
|
|
}; |
540
|
|
|
|
|
|
|
} |
541
|
|
|
|
|
|
|
|
542
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
### Scalar: LValue ### |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
__PACKAGE__->set( |
548
|
|
|
|
|
|
|
# LValue options |
549
|
|
|
|
|
|
|
lvalue => 'substr($lvalue, 0)', |
550
|
|
|
|
|
|
|
); |
551
|
|
|
|
|
|
|
|
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
sub lvalueify { |
554
|
4
|
|
|
4
|
1
|
10
|
my $self = &self; |
555
|
4
|
|
|
|
|
10
|
return _subst( $self->get('lvalue'), lvalue => $self->stringify(shift) ); |
556
|
|
|
|
|
|
|
} |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
|
559
|
|
|
|
|
|
|
|
560
|
|
|
|
|
|
|
### Scalar: VString ### |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
|
563
|
|
|
|
|
|
|
__PACKAGE__->set( |
564
|
|
|
|
|
|
|
# VString options |
565
|
|
|
|
|
|
|
vformat => 'v%vd', |
566
|
|
|
|
|
|
|
#vformat => 'v%*vd', |
567
|
|
|
|
|
|
|
#vsep => '.', |
568
|
|
|
|
|
|
|
); |
569
|
|
|
|
|
|
|
|
570
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
sub vstringify { |
572
|
4
|
|
|
4
|
1
|
10
|
my $self = &self; |
573
|
4
|
50
|
|
|
|
10
|
if ( defined( my $vsep = $self->get('vsep') ) ) { |
574
|
0
|
|
|
|
|
0
|
return sprintf $self->get('vformat'), $vsep, shift; |
575
|
|
|
|
|
|
|
} else { |
576
|
4
|
|
|
|
|
9
|
return sprintf $self->get('vformat'), shift; |
577
|
|
|
|
|
|
|
} |
578
|
|
|
|
|
|
|
} |
579
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
|
581
|
|
|
|
|
|
|
|
582
|
|
|
|
|
|
|
### Regexp ### |
583
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
__PACKAGE__->set( |
586
|
|
|
|
|
|
|
# Regexp options |
587
|
|
|
|
|
|
|
quote3 => '/', |
588
|
|
|
|
|
|
|
#_tr3 => q!tr\\/\\/\\!, |
589
|
|
|
|
|
|
|
q3 => 'qr', |
590
|
|
|
|
|
|
|
|
591
|
|
|
|
|
|
|
encode3 => { |
592
|
|
|
|
|
|
|
map( { ord( eval qq!"$_"! ) => $_ } qw( \0 \a \t \n \f \r \e ) ), |
593
|
|
|
|
|
|
|
#0x00 => '\\0', |
594
|
|
|
|
|
|
|
#0x07 => '\\a', |
595
|
|
|
|
|
|
|
#0x09 => '\\t', |
596
|
|
|
|
|
|
|
#0x0a => '\\n', |
597
|
|
|
|
|
|
|
#0x0c => '\\f', |
598
|
|
|
|
|
|
|
#0x0d => '\\r', |
599
|
|
|
|
|
|
|
#0x1b => '\\e', |
600
|
|
|
|
|
|
|
|
601
|
|
|
|
|
|
|
also => '[:cntrl:]', |
602
|
|
|
|
|
|
|
byte => '\\x%02x', |
603
|
|
|
|
|
|
|
wide => '\\x{%04x}', |
604
|
|
|
|
|
|
|
#vwide => '\\x{%06x}', |
605
|
|
|
|
|
|
|
}, |
606
|
|
|
|
|
|
|
); |
607
|
|
|
|
|
|
|
|
608
|
|
|
|
|
|
|
|
609
|
|
|
|
|
|
|
sub regexpify { |
610
|
4
|
|
|
4
|
1
|
7
|
my $self = &self; |
611
|
4
|
50
|
|
|
|
9
|
local $_ = shift if @_; |
612
|
4
|
|
|
|
|
7
|
local $@ = undef; |
613
|
|
|
|
|
|
|
|
614
|
4
|
|
|
|
|
9
|
my ( $quote3, $tr3 ) = $self->get(qw( quote3 _tr3 )); |
615
|
4
|
50
|
|
|
|
19
|
$self = $self->set( _tr3 => $tr3 = "tr\\$quote3\\$quote3\\" ) |
616
|
|
|
|
|
|
|
if ( not $tr3 ); |
617
|
4
|
|
50
|
|
|
325
|
my $quoter = eval $tr3 // die $@; |
618
|
4
|
50
|
33
|
|
|
33
|
my ( $open, $close ) |
619
|
|
|
|
|
|
|
= $self->_get_delim( |
620
|
|
|
|
|
|
|
shift // $quoter ? $self->_find_q($_) : $self->get('quote3') ); |
621
|
|
|
|
|
|
|
|
622
|
|
|
|
|
|
|
# Everything but the quotes should be escaped already. |
623
|
4
|
|
|
|
|
9
|
$self = $self->set( encode => $self->get('encode3') ); |
624
|
4
|
|
|
|
|
14
|
my $to_encode = $self->_to_encode( $open, $close ); |
625
|
4
|
|
|
|
|
42
|
s/([$to_encode])/$self->_encode_char($1)/eg; |
|
0
|
|
|
|
|
0
|
|
626
|
|
|
|
|
|
|
|
627
|
4
|
50
|
|
|
|
13
|
if ( $open =~ /\w/ ) { |
628
|
0
|
|
|
|
|
0
|
$open = ' ' . $open; |
629
|
0
|
|
|
|
|
0
|
$close = ' ' . $close; |
630
|
|
|
|
|
|
|
} |
631
|
|
|
|
|
|
|
|
632
|
4
|
|
|
|
|
10
|
$open = $self->get('q3') . $open; |
633
|
|
|
|
|
|
|
|
634
|
4
|
|
|
|
|
30
|
return sprintf '%s%s%s', $open, $_, $close; |
635
|
|
|
|
|
|
|
} |
636
|
|
|
|
|
|
|
|
637
|
|
|
|
|
|
|
|
638
|
|
|
|
|
|
|
|
639
|
|
|
|
|
|
|
### List/Array ### |
640
|
|
|
|
|
|
|
|
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
sub listify { |
643
|
24
|
|
|
24
|
1
|
49
|
my $self = &self; |
644
|
24
|
|
|
|
|
44
|
my @values; |
645
|
24
|
|
|
|
|
88
|
for ( my $i = 0; $i < @_; $i++ ) { |
646
|
116
|
|
|
|
|
204
|
my $value = $_[$i]; |
647
|
116
|
|
|
|
|
307
|
$self = $self->_push_position("[$i]"); |
648
|
116
|
|
|
|
|
236
|
push @values, $self->scalarify($value); |
649
|
116
|
|
|
|
|
249
|
$self->_pop_position; |
650
|
|
|
|
|
|
|
} |
651
|
24
|
|
|
|
|
60
|
return join( $self->get('list_sep'), @values ); |
652
|
|
|
|
|
|
|
} |
653
|
|
|
|
|
|
|
|
654
|
|
|
|
|
|
|
|
655
|
|
|
|
|
|
|
|
656
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
__PACKAGE__->set( |
658
|
|
|
|
|
|
|
# Array options |
659
|
|
|
|
|
|
|
array_ref => '[$_]', |
660
|
|
|
|
|
|
|
); |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
|
663
|
|
|
|
|
|
|
sub arrayify { |
664
|
24
|
|
|
24
|
1
|
74
|
my $self = &self; |
665
|
24
|
|
|
|
|
62
|
return _subst( $self->get('array_ref'), $self->listify(@_) ); |
666
|
|
|
|
|
|
|
} |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
|
670
|
|
|
|
|
|
|
### Hash ### |
671
|
|
|
|
|
|
|
|
672
|
|
|
|
|
|
|
|
673
|
|
|
|
|
|
|
sub is_keyword { |
674
|
322
|
|
|
322
|
1
|
548
|
my $self = &self; |
675
|
|
|
|
|
|
|
|
676
|
322
|
|
|
|
|
595
|
my $keyword_set = $self->get('keyword_set'); |
677
|
322
|
100
|
|
|
|
675
|
if ( not $keyword_set ) { |
678
|
63
|
|
50
|
|
|
116
|
my $keywords = $self->get('keywords') // []; |
679
|
63
|
50
|
|
|
|
141
|
return unless @$keywords; |
680
|
63
|
|
|
|
|
117
|
$keyword_set = { map { $_ => 1 } @$keywords }; |
|
63
|
|
|
|
|
236
|
|
681
|
63
|
|
|
|
|
148
|
$self->{keyword_set} = $keyword_set; |
682
|
|
|
|
|
|
|
} |
683
|
322
|
|
|
|
|
2422
|
return exists $keyword_set->{ +shift }; |
684
|
|
|
|
|
|
|
} |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
|
687
|
|
|
|
|
|
|
sub keyify { |
688
|
489
|
|
|
489
|
1
|
811
|
my $self = &self; |
689
|
489
|
50
|
|
|
|
1115
|
local $_ = shift if @_; |
690
|
|
|
|
|
|
|
|
691
|
489
|
50
|
|
|
|
927
|
return $self->undefify unless defined; |
692
|
489
|
50
|
|
|
|
817
|
return $_ if ref; |
693
|
|
|
|
|
|
|
|
694
|
489
|
100
|
33
|
|
|
887
|
if ( $self->is_numeric($_) ) { |
|
|
100
|
66
|
|
|
|
|
695
|
167
|
|
|
|
|
2642
|
return $self->numify($_); |
696
|
|
|
|
|
|
|
} elsif ( length() < $self->get('longstr') |
697
|
|
|
|
|
|
|
&& !$self->is_keyword($_) |
698
|
|
|
|
|
|
|
&& /\A-?[[:alpha:]_]\w*\z/ ) |
699
|
|
|
|
|
|
|
{ |
700
|
|
|
|
|
|
|
# If the key would be autoquoted by the fat-comma (=>), |
701
|
|
|
|
|
|
|
# then there is no need to quote it. |
702
|
|
|
|
|
|
|
|
703
|
290
|
|
|
|
|
950
|
return "$_"; # Make sure it's stringified. |
704
|
|
|
|
|
|
|
} |
705
|
32
|
|
|
|
|
105
|
return $self->stringify($_); |
706
|
|
|
|
|
|
|
} |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
|
709
|
|
|
|
|
|
|
|
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
sub keysort($$); |
712
|
|
|
|
|
|
|
BEGIN { |
713
|
5
|
|
|
5
|
|
43
|
no warnings 'qw'; |
|
5
|
|
|
|
|
36
|
|
|
5
|
|
|
|
|
590
|
|
714
|
5
|
|
|
5
|
|
48
|
my $keysort = String::Tools::stitch(qw( |
715
|
|
|
|
|
|
|
sub keysort($$) { |
716
|
|
|
|
|
|
|
my ( $a, $b ) = @_; |
717
|
|
|
|
|
|
|
my $numa = Datify->is_numeric($a); |
718
|
|
|
|
|
|
|
my $numb = Datify->is_numeric($b); |
719
|
|
|
|
|
|
|
return( |
720
|
|
|
|
|
|
|
( $numa && $numb ? $a <=> $b |
721
|
|
|
|
|
|
|
: $numa ? -1 |
722
|
|
|
|
|
|
|
: $numb ? +1 |
723
|
|
|
|
|
|
|
: $a_cmp__b ) |
724
|
|
|
|
|
|
|
|| $a cmp $b |
725
|
|
|
|
|
|
|
); |
726
|
|
|
|
|
|
|
} |
727
|
|
|
|
|
|
|
)); |
728
|
5
|
50
|
|
|
|
4161
|
my $a_cmp__b |
729
|
|
|
|
|
|
|
= $^V >= v5.16.0 |
730
|
|
|
|
|
|
|
? 'CORE::fc($a) cmp CORE::fc($b)' |
731
|
|
|
|
|
|
|
: 'lc($a) cmp lc($b)'; |
732
|
5
|
|
|
|
|
43
|
$keysort = String::Tools::subst( $keysort, a_cmp__b => $a_cmp__b ); |
733
|
5
|
50
|
50
|
1225
|
1
|
7076
|
eval($keysort) or $@ and die $@; |
|
1225
|
|
100
|
|
|
3322
|
|
|
1225
|
|
|
|
|
2577
|
|
|
1225
|
|
|
|
|
35153
|
|
|
1225
|
|
|
|
|
37219
|
|
734
|
|
|
|
|
|
|
} |
735
|
|
|
|
|
|
|
|
736
|
|
|
|
|
|
|
|
737
|
|
|
|
|
|
|
|
738
|
|
|
|
|
|
|
sub hashkeys { |
739
|
58
|
|
|
58
|
1
|
96
|
my $self = shift; |
740
|
58
|
|
|
|
|
82
|
my $hash = shift; |
741
|
|
|
|
|
|
|
|
742
|
58
|
|
|
|
|
212
|
my @keys = keys %$hash; |
743
|
58
|
50
|
|
|
|
122
|
if ( my $ref = ref( my $keyfilter = $self->get('keyfilter') ) ) { |
744
|
0
|
|
|
|
|
0
|
my $keyfilternot = !$self->get('keyfilterdefault'); |
745
|
0
|
|
|
|
|
0
|
my $keyfilterdefault = !$keyfilternot; |
746
|
0
|
0
|
0
|
|
|
0
|
if ( $ref eq 'ARRAY' || $ref eq 'HASH' ) { |
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
|
|
0
|
|
|
|
|
|
747
|
|
|
|
|
|
|
my %keyfilterhash |
748
|
|
|
|
|
|
|
= $ref eq 'ARRAY' |
749
|
0
|
0
|
|
|
|
0
|
? ( map { $_ => $keyfilternot } @$keyfilter ) |
|
0
|
|
|
|
|
0
|
|
750
|
|
|
|
|
|
|
: %$keyfilter; |
751
|
|
|
|
|
|
|
$self->{keyfilter} = $keyfilter = sub { |
752
|
|
|
|
|
|
|
exists $keyfilterhash{$_} |
753
|
0
|
0
|
|
0
|
|
0
|
? $keyfilterhash{$_} |
754
|
|
|
|
|
|
|
: $keyfilterdefault; |
755
|
0
|
|
|
|
|
0
|
}; |
756
|
|
|
|
|
|
|
} elsif ( $ref eq 'CODE' ) { |
757
|
|
|
|
|
|
|
# No-op, just use the code provided |
758
|
|
|
|
|
|
|
} elsif ( $ref eq 'Regexp' ) { |
759
|
0
|
|
|
|
|
0
|
my $keyfilterregexp = $keyfilter; |
760
|
|
|
|
|
|
|
$self->{keyfilter} = $keyfilter = sub { |
761
|
0
|
0
|
|
0
|
|
0
|
m/$keyfilterregexp/ ? $keyfilternot : $keyfilterdefault; |
762
|
0
|
|
|
|
|
0
|
}; |
763
|
|
|
|
|
|
|
} elsif ( $ref eq 'SCALAR' ) { |
764
|
0
|
|
|
|
|
0
|
my $keyfiltervalue = $$keyfilter; |
765
|
0
|
|
|
0
|
|
0
|
$self->{keyfilter} = $keyfilter = sub {$keyfiltervalue}; |
|
0
|
|
|
|
|
0
|
|
766
|
|
|
|
|
|
|
} |
767
|
0
|
|
|
|
|
0
|
@keys = grep { $keyfilter->() } @keys; |
|
0
|
|
|
|
|
0
|
|
768
|
|
|
|
|
|
|
} |
769
|
58
|
50
|
|
|
|
120
|
if ( my $keysort = $self->get('keysort') ) { |
770
|
58
|
|
|
|
|
934
|
@keys = sort $keysort @keys; |
771
|
|
|
|
|
|
|
} |
772
|
58
|
|
|
|
|
247
|
return @keys; |
773
|
|
|
|
|
|
|
} |
774
|
|
|
|
|
|
|
|
775
|
|
|
|
|
|
|
sub hashkeyvals { |
776
|
28
|
|
|
28
|
0
|
42
|
my $self = shift; |
777
|
28
|
|
|
|
|
43
|
my $hash = shift; |
778
|
|
|
|
|
|
|
|
779
|
28
|
|
|
|
|
75
|
return map { $_ => $hash->{$_} } $self->hashkeys($hash); |
|
288
|
|
|
|
|
608
|
|
780
|
|
|
|
|
|
|
} |
781
|
|
|
|
|
|
|
|
782
|
|
|
|
|
|
|
|
783
|
|
|
|
|
|
|
sub pairify { |
784
|
28
|
|
|
28
|
1
|
71
|
my $self = &self; |
785
|
28
|
50
|
|
|
|
81
|
if (1 == @_) { |
786
|
28
|
|
|
|
|
73
|
my $ref = Scalar::Util::reftype $_[0]; |
787
|
28
|
50
|
|
|
|
96
|
if ( $ref eq 'ARRAY' ) { @_ = @{ +shift } } |
|
0
|
50
|
|
|
|
0
|
|
|
0
|
|
|
|
|
0
|
|
788
|
28
|
|
|
|
|
78
|
elsif ( $ref eq 'HASH' ) { @_ = $self->hashkeyvals(shift) } |
789
|
|
|
|
|
|
|
} |
790
|
|
|
|
|
|
|
# Use for loop in order to preserve the order of @_, |
791
|
|
|
|
|
|
|
# rather than each %{ { @_ } }, which would mix-up the order. |
792
|
28
|
|
|
|
|
63
|
my @list; |
793
|
28
|
|
|
|
|
73
|
my $pair = $self->get('pair'); |
794
|
28
|
|
|
|
|
96
|
for ( my $i = 0; $i < @_ - 1; $i += 2 ) { |
795
|
288
|
|
|
|
|
19387
|
my ( $k, $v ) = @_[ $i, $i + 1 ]; |
796
|
288
|
|
|
|
|
668
|
my $key = $self->keyify($k); |
797
|
288
|
|
|
|
|
761
|
$self = $self->_push_position("{$key}"); |
798
|
288
|
|
|
|
|
595
|
my $val = $self->scalarify($v); |
799
|
288
|
|
|
|
|
694
|
$self->_pop_position; |
800
|
288
|
|
|
|
|
651
|
push @list, _subst( $pair, key => $key, value => $val ); |
801
|
|
|
|
|
|
|
} |
802
|
28
|
|
|
|
|
1509
|
return join( $self->get('list_sep'), @list ); |
803
|
|
|
|
|
|
|
} |
804
|
|
|
|
|
|
|
|
805
|
|
|
|
|
|
|
|
806
|
|
|
|
|
|
|
|
807
|
|
|
|
|
|
|
|
808
|
|
|
|
|
|
|
__PACKAGE__->set( |
809
|
|
|
|
|
|
|
# Hash options |
810
|
|
|
|
|
|
|
hash_ref => '{$_}', |
811
|
|
|
|
|
|
|
pair => '$key => $value', |
812
|
|
|
|
|
|
|
keysort => \&Datify::keysort, |
813
|
|
|
|
|
|
|
keyfilter => undef, |
814
|
|
|
|
|
|
|
keyfilterdefault => 1, |
815
|
|
|
|
|
|
|
keywords => [qw(undef)], |
816
|
|
|
|
|
|
|
#keyword_set => { 'undef' => 1 }, |
817
|
|
|
|
|
|
|
); |
818
|
|
|
|
|
|
|
|
819
|
|
|
|
|
|
|
|
820
|
|
|
|
|
|
|
sub hashify { |
821
|
28
|
|
|
28
|
1
|
64
|
my $self = &self; |
822
|
28
|
|
|
|
|
79
|
return _subst( $self->get('hash_ref'), $self->pairify(@_) ); |
823
|
|
|
|
|
|
|
} |
824
|
|
|
|
|
|
|
|
825
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
|
827
|
|
|
|
|
|
|
### Objects ### |
828
|
|
|
|
|
|
|
|
829
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
sub overloaded { |
831
|
32
|
|
|
32
|
1
|
60
|
my $self = &self; |
832
|
32
|
50
|
|
|
|
68
|
my $object = @_ ? shift : $_; |
833
|
|
|
|
|
|
|
|
834
|
32
|
50
|
33
|
|
|
173
|
return unless defined( Scalar::Util::blessed($object) ) |
835
|
|
|
|
|
|
|
&& overload::Overloaded($object); |
836
|
|
|
|
|
|
|
|
837
|
0
|
|
0
|
|
|
0
|
my $overloads = $self->get('overloads') || []; |
838
|
0
|
|
|
|
|
0
|
foreach my $overload (@$overloads) { |
839
|
0
|
0
|
|
|
|
0
|
if ( my $method = overload::Method( $object => $overload ) ) { |
840
|
0
|
|
|
|
|
0
|
return $method; |
841
|
|
|
|
|
|
|
} |
842
|
|
|
|
|
|
|
} |
843
|
0
|
|
|
|
|
0
|
return; |
844
|
|
|
|
|
|
|
} |
845
|
|
|
|
|
|
|
|
846
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
|
848
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
__PACKAGE__->set( |
850
|
|
|
|
|
|
|
# Object options |
851
|
|
|
|
|
|
|
overloads => [ '""', '0+' ], |
852
|
|
|
|
|
|
|
object => 'bless($data, $class_str)', |
853
|
|
|
|
|
|
|
#object => '$class->new($data)', |
854
|
|
|
|
|
|
|
#object => '$class=$data', |
855
|
|
|
|
|
|
|
); |
856
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
|
858
|
|
|
|
|
|
|
sub objectify { |
859
|
32
|
|
|
32
|
1
|
59
|
my $self = &self; |
860
|
32
|
50
|
|
|
|
71
|
my $object = @_ ? shift : $_; |
861
|
|
|
|
|
|
|
|
862
|
32
|
50
|
|
|
|
91
|
return $self->scalarify($object) |
863
|
|
|
|
|
|
|
unless defined( my $class = Scalar::Util::blessed($object) ); |
864
|
|
|
|
|
|
|
|
865
|
32
|
|
|
|
|
58
|
my $data; |
866
|
32
|
50
|
|
|
|
59
|
if (0) { |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
867
|
0
|
|
|
|
|
0
|
} elsif ( my $code = $self->_find_handler($class) ) { |
868
|
0
|
|
|
|
|
0
|
return $self->$code($object); |
869
|
|
|
|
|
|
|
} elsif ( my $method = $self->overloaded($object) ) { |
870
|
0
|
|
|
|
|
0
|
$data = $self->scalarify( $object->$method() ); |
871
|
|
|
|
|
|
|
} elsif ( my $attrkeyvals = $object->can('_attrkeyvals') ) { |
872
|
|
|
|
|
|
|
# TODO: Look this up via meta-objects |
873
|
0
|
|
|
|
|
0
|
$data = $self->hashify( $object->$attrkeyvals() ); |
874
|
|
|
|
|
|
|
} else { |
875
|
32
|
|
|
|
|
1837
|
$data = Scalar::Util::reftype $object; |
876
|
|
|
|
|
|
|
|
877
|
32
|
50
|
|
|
|
179
|
$data |
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
878
|
|
|
|
|
|
|
= $data eq 'ARRAY' ? $self->arrayify( @$object ) |
879
|
|
|
|
|
|
|
: $data eq 'CODE' ? $self->codeify( $object ) |
880
|
|
|
|
|
|
|
: $data eq 'FORMAT' ? $self->formatify( $object ) |
881
|
|
|
|
|
|
|
: $data eq 'GLOB' ? $self->globify( $object ) |
882
|
|
|
|
|
|
|
: $data eq 'HASH' ? $self->hashify( $object ) |
883
|
|
|
|
|
|
|
: $data eq 'IO' ? $self->ioify( $object ) |
884
|
|
|
|
|
|
|
: $data eq 'REF' ? $self->refify( $$object ) |
885
|
|
|
|
|
|
|
: $data eq 'REGEXP' ? $self->regexpify( $object ) |
886
|
|
|
|
|
|
|
: $data eq 'SCALAR' ? $self->refify( $$object ) |
887
|
|
|
|
|
|
|
: "*UNKNOWN{$data}"; |
888
|
|
|
|
|
|
|
} |
889
|
|
|
|
|
|
|
|
890
|
32
|
|
|
|
|
2209
|
return _subst( |
891
|
|
|
|
|
|
|
$self->get('object'), |
892
|
|
|
|
|
|
|
class_str => $self->stringify($class), |
893
|
|
|
|
|
|
|
class => $class, |
894
|
|
|
|
|
|
|
data => $data |
895
|
|
|
|
|
|
|
); |
896
|
|
|
|
|
|
|
} |
897
|
|
|
|
|
|
|
|
898
|
|
|
|
|
|
|
|
899
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
### Objects: IO ### |
901
|
|
|
|
|
|
|
|
902
|
|
|
|
|
|
|
|
903
|
|
|
|
|
|
|
__PACKAGE__->set( |
904
|
|
|
|
|
|
|
# IO options |
905
|
|
|
|
|
|
|
io => '*$name{IO}', |
906
|
|
|
|
|
|
|
); |
907
|
|
|
|
|
|
|
|
908
|
|
|
|
|
|
|
|
909
|
|
|
|
|
|
|
|
910
|
|
|
|
|
|
|
sub ioify { |
911
|
4
|
|
|
4
|
1
|
6
|
my $self = &self; |
912
|
4
|
50
|
|
|
|
10
|
my $io = @_ ? shift : $_; |
913
|
|
|
|
|
|
|
|
914
|
4
|
|
|
|
|
7
|
my $ioname = 'UNKNOWN'; |
915
|
4
|
|
|
|
|
8
|
foreach my $ioe (qw( IN OUT ERR )) { |
916
|
5
|
|
|
5
|
|
42
|
no strict 'refs'; |
|
5
|
|
|
|
|
11
|
|
|
5
|
|
|
|
|
14957
|
|
917
|
8
|
100
|
|
|
|
11
|
if ( *{"main::STD$ioe"}{IO} == $io ) { |
|
8
|
|
|
|
|
31
|
|
918
|
4
|
|
|
|
|
7
|
$ioname = "STD$ioe"; |
919
|
4
|
|
|
|
|
7
|
last; |
920
|
|
|
|
|
|
|
} |
921
|
|
|
|
|
|
|
} |
922
|
|
|
|
|
|
|
# TODO |
923
|
|
|
|
|
|
|
#while ( my ( $name, $glob ) = each %main:: ) { |
924
|
|
|
|
|
|
|
# no strict 'refs'; |
925
|
|
|
|
|
|
|
# if ( defined( *{$glob}{IO} ) && *{$glob}{IO} == $io ) { |
926
|
|
|
|
|
|
|
# keys %main::; # We're done, so reset each() |
927
|
|
|
|
|
|
|
# $ioname = $name; |
928
|
|
|
|
|
|
|
# last; |
929
|
|
|
|
|
|
|
# } |
930
|
|
|
|
|
|
|
#} |
931
|
4
|
|
|
|
|
11
|
return _subst( $self->get('io'), name => $ioname ); |
932
|
|
|
|
|
|
|
} |
933
|
|
|
|
|
|
|
|
934
|
|
|
|
|
|
|
|
935
|
|
|
|
|
|
|
|
936
|
|
|
|
|
|
|
### Other ### |
937
|
|
|
|
|
|
|
|
938
|
|
|
|
|
|
|
|
939
|
|
|
|
|
|
|
__PACKAGE__->set( |
940
|
|
|
|
|
|
|
# Code options |
941
|
|
|
|
|
|
|
code => 'sub {$body}', |
942
|
|
|
|
|
|
|
codename => '\&$codename', |
943
|
|
|
|
|
|
|
body => '...', |
944
|
|
|
|
|
|
|
); |
945
|
|
|
|
|
|
|
|
946
|
|
|
|
|
|
|
|
947
|
|
|
|
|
|
|
sub codeify { |
948
|
8
|
|
|
8
|
1
|
23
|
my $self = &self; |
949
|
|
|
|
|
|
|
|
950
|
8
|
|
|
|
|
22
|
my $template = $self->get('code'); |
951
|
8
|
|
|
|
|
25
|
my %data = ( body => $self->get('body') ); |
952
|
8
|
50
|
33
|
|
|
39
|
if ( @_ && defined( $_[0] ) ) { |
953
|
8
|
|
|
|
|
14
|
local $_ = shift; |
954
|
8
|
50
|
|
|
|
29
|
if ( my $ref = Scalar::Util::reftype($_) ) { |
955
|
8
|
50
|
|
|
|
18
|
if ( $ref eq 'CODE' ) { |
956
|
8
|
100
|
|
|
|
78
|
if ( ( my $subname = Sub::Util::subname($_) ) |
957
|
|
|
|
|
|
|
!~ /\A(?:\w+\::)*__ANON__\z/ ) |
958
|
|
|
|
|
|
|
{ |
959
|
4
|
|
33
|
|
|
14
|
$template = $self->get('codename') // $template; |
960
|
4
|
|
|
|
|
19
|
%data = ( codename => $subname ); |
961
|
|
|
|
|
|
|
} |
962
|
|
|
|
|
|
|
} else { |
963
|
0
|
|
|
|
|
0
|
%data = ( body => $self->scalarify($_) ); |
964
|
|
|
|
|
|
|
} |
965
|
|
|
|
|
|
|
} else { |
966
|
0
|
|
|
|
|
0
|
%data = ( body => $_ ); |
967
|
|
|
|
|
|
|
} |
968
|
|
|
|
|
|
|
} |
969
|
8
|
|
|
|
|
29
|
return _subst( $template, %data ); |
970
|
|
|
|
|
|
|
} |
971
|
|
|
|
|
|
|
|
972
|
|
|
|
|
|
|
|
973
|
|
|
|
|
|
|
|
974
|
|
|
|
|
|
|
|
975
|
|
|
|
|
|
|
__PACKAGE__->set( |
976
|
|
|
|
|
|
|
# Reference options |
977
|
|
|
|
|
|
|
reference => '\\$_', |
978
|
|
|
|
|
|
|
dereference => '$referent->$place', |
979
|
|
|
|
|
|
|
nested => '$referent$place', |
980
|
|
|
|
|
|
|
); |
981
|
|
|
|
|
|
|
|
982
|
|
|
|
|
|
|
|
983
|
|
|
|
|
|
|
sub refify { |
984
|
52
|
|
|
52
|
1
|
96
|
my $self = &self; |
985
|
52
|
50
|
|
|
|
122
|
local $_ = shift if @_; |
986
|
52
|
|
|
|
|
107
|
return _subst( $self->get('reference'), $self->scalarify($_) ); |
987
|
|
|
|
|
|
|
} |
988
|
|
|
|
|
|
|
|
989
|
|
|
|
|
|
|
|
990
|
|
|
|
|
|
|
|
991
|
|
|
|
|
|
|
|
992
|
|
|
|
|
|
|
__PACKAGE__->set( |
993
|
|
|
|
|
|
|
# Format options |
994
|
|
|
|
|
|
|
format => "format UNKNOWN =\n.\n", |
995
|
|
|
|
|
|
|
); |
996
|
|
|
|
|
|
|
|
997
|
|
|
|
|
|
|
|
998
|
|
|
|
|
|
|
sub formatify { |
999
|
4
|
|
|
4
|
1
|
10
|
my $self = &self; |
1000
|
|
|
|
|
|
|
#Carp::croak "Unhandled type: ", ref shift; |
1001
|
4
|
|
|
|
|
8
|
return $self->get('format'); |
1002
|
|
|
|
|
|
|
} |
1003
|
|
|
|
|
|
|
|
1004
|
|
|
|
|
|
|
|
1005
|
|
|
|
|
|
|
|
1006
|
|
|
|
|
|
|
|
1007
|
|
|
|
|
|
|
sub globify { |
1008
|
4
|
|
|
4
|
1
|
8
|
my $self = &self; |
1009
|
4
|
|
|
|
|
15
|
my $name = '' . shift; |
1010
|
4
|
50
|
|
|
|
147
|
if ( $name =~ /^\*$package\::(?:$word|$digits)?$/ ) { |
1011
|
4
|
|
|
|
|
19
|
$name =~ s/^\*main::/*::/; |
1012
|
|
|
|
|
|
|
} else { |
1013
|
0
|
|
|
|
|
0
|
$name =~ s/^\*($package\::.+)/'*{' . $self->stringify($1) . '}'/e; |
|
0
|
|
|
|
|
0
|
|
1014
|
|
|
|
|
|
|
} |
1015
|
4
|
|
|
|
|
16
|
return $name; |
1016
|
|
|
|
|
|
|
} |
1017
|
|
|
|
|
|
|
|
1018
|
|
|
|
|
|
|
|
1019
|
|
|
|
|
|
|
|
1020
|
|
|
|
|
|
|
sub beautify { |
1021
|
0
|
|
|
0
|
1
|
0
|
my $self = &self; |
1022
|
0
|
|
|
|
|
0
|
my ( $method, @params ) = @_; |
1023
|
|
|
|
|
|
|
|
1024
|
0
|
|
0
|
|
|
0
|
$method = $self->can($method) || die "Cannot $method"; |
1025
|
|
|
|
|
|
|
|
1026
|
0
|
0
|
|
|
|
0
|
if ( my $beauty = $self->get('beautify') ) { |
1027
|
0
|
|
|
|
|
0
|
return $beauty->( $self->$method(@params) ); |
1028
|
|
|
|
|
|
|
} else { |
1029
|
0
|
|
|
|
|
0
|
return $self->$method(@params); |
1030
|
|
|
|
|
|
|
} |
1031
|
|
|
|
|
|
|
} |
1032
|
|
|
|
|
|
|
|
1033
|
|
|
|
|
|
|
### Private Methods & Settings ### |
1034
|
|
|
|
|
|
|
### Do not use these methods & settings outside of this package, |
1035
|
|
|
|
|
|
|
### they are subject to change or disappear at any time. |
1036
|
|
|
|
|
|
|
sub class { |
1037
|
11
|
100
|
|
11
|
0
|
8470
|
return scalar caller unless @_; |
1038
|
10
|
|
|
|
|
18
|
my $caller = caller; |
1039
|
10
|
|
|
|
|
15
|
my $class; |
1040
|
10
|
50
|
33
|
|
|
52
|
if ( defined( $class = Scalar::Util::blessed( $_[0] ) ) |
|
|
|
66
|
|
|
|
|
1041
|
|
|
|
|
|
|
|| ( !ref( $_[0] ) && length( $class = $_[0] ) ) ) |
1042
|
|
|
|
|
|
|
{ |
1043
|
10
|
100
|
|
|
|
44
|
if ( $class->isa($caller) ) { |
1044
|
8
|
|
|
|
|
12
|
shift; |
1045
|
8
|
|
|
|
|
20
|
return $class; |
1046
|
|
|
|
|
|
|
} |
1047
|
|
|
|
|
|
|
} |
1048
|
2
|
|
|
|
|
6
|
return $caller; |
1049
|
|
|
|
|
|
|
} |
1050
|
|
|
|
|
|
|
sub self { |
1051
|
7739
|
|
|
7739
|
0
|
10878
|
my $self = shift; |
1052
|
7739
|
100
|
|
|
|
21219
|
return defined( Scalar::Util::blessed($self) ) ? $self : $self->new(); |
1053
|
|
|
|
|
|
|
} |
1054
|
9527
|
|
100
|
9527
|
|
41261
|
sub _internal { return $_[0]->isa( scalar caller( 1 + ( $_[1] // 0 ) ) ) } |
1055
|
|
|
|
|
|
|
sub _private { |
1056
|
6534
|
100
|
|
6534
|
|
10549
|
Carp::croak('Illegal use of private method') unless $_[0]->_internal(1); |
1057
|
|
|
|
|
|
|
} |
1058
|
|
|
|
|
|
|
sub _settings() { |
1059
|
6534
|
|
|
6534
|
|
11766
|
&_private; |
1060
|
6533
|
|
|
|
|
11615
|
\state %SETTINGS; |
1061
|
|
|
|
|
|
|
} |
1062
|
|
|
|
|
|
|
|
1063
|
|
|
|
|
|
|
sub _nameify { |
1064
|
44
|
50
|
|
44
|
|
100
|
local $_ = shift if @_; |
1065
|
44
|
|
|
|
|
158
|
s/::/_/g; |
1066
|
44
|
|
|
|
|
298
|
return lc() . 'ify'; |
1067
|
|
|
|
|
|
|
} |
1068
|
|
|
|
|
|
|
sub _find_handler { |
1069
|
32
|
|
|
32
|
|
50
|
my $self = shift; |
1070
|
32
|
|
|
|
|
43
|
my $class = shift; |
1071
|
|
|
|
|
|
|
|
1072
|
32
|
|
|
|
|
141
|
my $isa = mro::get_linear_isa($class); |
1073
|
32
|
|
|
|
|
71
|
foreach my $c (@$isa) { |
1074
|
44
|
50
|
|
|
|
84
|
next unless my $code = $self->can( _nameify($c) ); |
1075
|
0
|
|
|
|
|
0
|
return $code; |
1076
|
|
|
|
|
|
|
} |
1077
|
32
|
|
|
|
|
107
|
return; |
1078
|
|
|
|
|
|
|
} |
1079
|
|
|
|
|
|
|
|
1080
|
|
|
|
|
|
|
sub _subst { |
1081
|
531
|
50
|
|
531
|
|
1287
|
die "Cannot subst on an undefined value" |
1082
|
|
|
|
|
|
|
unless defined $_[0]; |
1083
|
531
|
|
|
|
|
1834
|
goto &String::Tools::subst; |
1084
|
|
|
|
|
|
|
} |
1085
|
|
|
|
|
|
|
|
1086
|
|
|
|
|
|
|
sub _get_delim { |
1087
|
464
|
|
|
464
|
|
654
|
my $self = shift; |
1088
|
464
|
|
|
|
|
640
|
my $open = shift; |
1089
|
|
|
|
|
|
|
|
1090
|
464
|
|
|
|
|
579
|
my $close; |
1091
|
464
|
50
|
|
|
|
961
|
if ( 1 < length $open ) { |
1092
|
0
|
|
0
|
|
|
0
|
my $qpairs = $self->get('qpairs') || []; |
1093
|
0
|
|
|
|
|
0
|
my %qpairs = map { $_ => 1 } @$qpairs; |
|
0
|
|
|
|
|
0
|
|
1094
|
0
|
0
|
|
|
|
0
|
if ( $qpairs{$open} ) { |
1095
|
0
|
|
|
|
|
0
|
( $open, $close ) = split //, $open, 2; |
1096
|
|
|
|
|
|
|
} else { |
1097
|
0
|
|
|
|
|
0
|
( $open ) = split //, $open, 1 |
1098
|
|
|
|
|
|
|
} |
1099
|
|
|
|
|
|
|
} |
1100
|
464
|
50
|
|
|
|
844
|
$close = $open unless $close; |
1101
|
|
|
|
|
|
|
|
1102
|
464
|
|
|
|
|
1035
|
return $open, $close; |
1103
|
|
|
|
|
|
|
} |
1104
|
|
|
|
|
|
|
|
1105
|
|
|
|
|
|
|
sub _to_encode { |
1106
|
464
|
|
|
464
|
|
662
|
my $self = shift; |
1107
|
|
|
|
|
|
|
|
1108
|
464
|
|
|
|
|
811
|
my $encode = $self->get('encode'); |
1109
|
|
|
|
|
|
|
|
1110
|
|
|
|
|
|
|
# Ignore the settings for byte, byte2, byte3, byte4, vwide, wide, |
1111
|
|
|
|
|
|
|
# and utf |
1112
|
|
|
|
|
|
|
my @encode |
1113
|
464
|
|
|
|
|
1220
|
= grep { !(/\A(?:also|byte[234]?|v?wide|utf)\z/) } keys(%$encode); |
|
1665
|
|
|
|
|
4822
|
|
1114
|
|
|
|
|
|
|
|
1115
|
464
|
|
100
|
|
|
1602
|
my @ranges = ( $encode->{also} // () ); |
1116
|
464
|
|
|
|
|
915
|
foreach my $element (@_) { |
1117
|
1048
|
50
|
|
|
|
2680
|
if ( Scalar::Util::looks_like_number($element) ) { |
|
|
50
|
|
|
|
|
|
1118
|
0
|
|
|
|
|
0
|
push @encode, $element; |
1119
|
|
|
|
|
|
|
} elsif ( length($element) == 1 ) { |
1120
|
|
|
|
|
|
|
# An actual character, lets get the ordinal value and use that |
1121
|
1048
|
|
|
|
|
1842
|
push @encode, ord($element); |
1122
|
|
|
|
|
|
|
} else { |
1123
|
|
|
|
|
|
|
# Something longer, it must be a range of chars, |
1124
|
|
|
|
|
|
|
# like [:cntrl:], \x00-\x7f, or similar |
1125
|
0
|
|
|
|
|
0
|
push @ranges, $element; |
1126
|
|
|
|
|
|
|
} |
1127
|
|
|
|
|
|
|
} |
1128
|
|
|
|
|
|
|
@encode = map { |
1129
|
|
|
|
|
|
|
# Encode characters in their \xXX or \x{XXXX} notation, |
1130
|
|
|
|
|
|
|
# to get the literal values |
1131
|
2079
|
100
|
|
|
|
6001
|
sprintf( $_ <= 255 ? '\\x%02x' : '\\x{%04x}', $_ ) |
1132
|
|
|
|
|
|
|
} sort { |
1133
|
464
|
|
|
|
|
1454
|
$a <=> $b |
|
3573
|
|
|
|
|
5151
|
|
1134
|
|
|
|
|
|
|
} @encode; |
1135
|
|
|
|
|
|
|
|
1136
|
464
|
|
|
|
|
1666
|
return join( '', @encode, @ranges ); |
1137
|
|
|
|
|
|
|
} |
1138
|
|
|
|
|
|
|
|
1139
|
|
|
|
|
|
|
sub _encode_ord2utf16 { |
1140
|
6
|
|
|
6
|
|
9
|
my $self = shift; |
1141
|
6
|
|
|
|
|
7
|
my $ord = shift; |
1142
|
|
|
|
|
|
|
|
1143
|
6
|
|
|
|
|
11
|
my $encode = $self->get('encode'); |
1144
|
6
|
|
|
|
|
11
|
my $format = $encode->{wide}; |
1145
|
6
|
|
|
|
|
10
|
my @wides = (); |
1146
|
6
|
100
|
33
|
|
|
28
|
if (0) { |
|
|
50
|
|
|
|
|
|
1147
|
0
|
50
|
|
|
|
0
|
} elsif ( 0x0000 <= $ord && $ord <= 0xffff ) { |
1148
|
5
|
50
|
33
|
|
|
13
|
if ( 0xd800 <= $ord && $ord <= 0xdfff ) { |
1149
|
0
|
|
|
|
|
0
|
die "Illegal character $ord"; |
1150
|
|
|
|
|
|
|
} |
1151
|
|
|
|
|
|
|
|
1152
|
5
|
|
|
|
|
12
|
@wides = ( $ord ); |
1153
|
|
|
|
|
|
|
} elsif ( 0x01_0000 <= $ord && $ord <= 0x10_ffff ) { |
1154
|
1
|
|
33
|
|
|
6
|
$format = $encode->{vwide} || $format x 2; |
1155
|
|
|
|
|
|
|
|
1156
|
1
|
|
|
|
|
4
|
$ord -= 0x01_0000; |
1157
|
1
|
|
|
|
|
3
|
my $ord2 = 0xdc00 + ( 0x3ff & $ord ); |
1158
|
1
|
|
|
|
|
3
|
$ord >>= 10; |
1159
|
1
|
|
|
|
|
2
|
my $ord1 = 0xd800 + ( 0x3ff & $ord ); |
1160
|
1
|
|
|
|
|
3
|
@wides = ( $ord1, $ord2 ); |
1161
|
|
|
|
|
|
|
} else { |
1162
|
0
|
|
|
|
|
0
|
die "Illegal character $ord"; |
1163
|
|
|
|
|
|
|
} |
1164
|
6
|
|
|
|
|
41
|
return sprintf( $format, @wides ); |
1165
|
|
|
|
|
|
|
} |
1166
|
|
|
|
|
|
|
sub _encode_ord2utf8 { |
1167
|
6
|
|
|
6
|
|
12
|
my $self = shift; |
1168
|
6
|
|
|
|
|
8
|
my $ord = shift; |
1169
|
|
|
|
|
|
|
|
1170
|
6
|
|
|
|
|
11
|
my @bytes = (); |
1171
|
6
|
|
|
|
|
9
|
my $format = undef; |
1172
|
|
|
|
|
|
|
|
1173
|
6
|
|
|
|
|
12
|
my $encode = $self->get('encode'); |
1174
|
6
|
50
|
66
|
|
|
46
|
if (0) { |
|
|
100
|
66
|
|
|
|
|
|
|
100
|
33
|
|
|
|
|
|
|
50
|
|
|
|
|
|
1175
|
0
|
50
|
|
|
|
0
|
} elsif ( 0x00 <= $ord && $ord <= 0x7f ) { |
1176
|
|
|
|
|
|
|
# 1 byte represenstation |
1177
|
0
|
|
|
|
|
0
|
$format = $encode->{byte}; |
1178
|
0
|
|
|
|
|
0
|
@bytes = ( $ord ); |
1179
|
|
|
|
|
|
|
} elsif ( 0x0080 <= $ord && $ord <= 0x07ff ) { |
1180
|
|
|
|
|
|
|
# 2 byte represenstation |
1181
|
4
|
|
33
|
|
|
9
|
$format = $encode->{byte2} || $format x 2; |
1182
|
|
|
|
|
|
|
|
1183
|
4
|
|
|
|
|
9
|
my $ord2 = 0x80 + ( 0x3f & $ord ); |
1184
|
4
|
|
|
|
|
7
|
$ord >>= 6; |
1185
|
4
|
|
|
|
|
7
|
my $ord1 = 0xc0 + ( 0x1f & $ord ); |
1186
|
4
|
|
|
|
|
9
|
@bytes = ( $ord1, $ord2 ); |
1187
|
|
|
|
|
|
|
} elsif ( 0x0800 <= $ord && $ord <= 0xffff ) { |
1188
|
1
|
50
|
33
|
|
|
6
|
if ( 0xd800 <= $ord && $ord <= 0xdfff ) { |
1189
|
0
|
|
|
|
|
0
|
die "Illegal character $ord"; |
1190
|
|
|
|
|
|
|
} |
1191
|
|
|
|
|
|
|
|
1192
|
|
|
|
|
|
|
# 3 byte represenstation |
1193
|
1
|
|
33
|
|
|
3
|
$format = $encode->{byte3} || $format x 3; |
1194
|
|
|
|
|
|
|
|
1195
|
1
|
|
|
|
|
3
|
my $ord3 = 0x80 + ( 0x3f & $ord ); |
1196
|
1
|
|
|
|
|
2
|
$ord >>= 6; |
1197
|
1
|
|
|
|
|
3
|
my $ord2 = 0x80 + ( 0x3f & $ord ); |
1198
|
1
|
|
|
|
|
2
|
$ord >>= 6; |
1199
|
1
|
|
|
|
|
3
|
my $ord1 = 0xe0 + ( 0x0f & $ord ); |
1200
|
1
|
|
|
|
|
2
|
@bytes = ( $ord1, $ord2, $ord3 ); |
1201
|
|
|
|
|
|
|
} elsif ( 0x01_0000 <= $ord && $ord <= 0x10_ffff ) { |
1202
|
|
|
|
|
|
|
# 4 byte represenstation |
1203
|
1
|
|
33
|
|
|
3
|
$format = $encode->{byte4} || $format x 4; |
1204
|
|
|
|
|
|
|
|
1205
|
1
|
|
|
|
|
3
|
my $ord4 = 0x80 + ( 0x3f & $ord ); |
1206
|
1
|
|
|
|
|
3
|
$ord >>= 6; |
1207
|
1
|
|
|
|
|
3
|
my $ord3 = 0x80 + ( 0x3f & $ord ); |
1208
|
1
|
|
|
|
|
3
|
$ord >>= 6; |
1209
|
1
|
|
|
|
|
2
|
my $ord2 = 0x80 + ( 0x3f & $ord ); |
1210
|
1
|
|
|
|
|
2
|
$ord >>= 6; |
1211
|
1
|
|
|
|
|
3
|
my $ord1 = 0xf0 + ( 0x07 & $ord ); |
1212
|
1
|
|
|
|
|
3
|
@bytes = ( $ord1, $ord2, $ord3, $ord4 ); |
1213
|
|
|
|
|
|
|
} else { |
1214
|
0
|
|
|
|
|
0
|
die "Illegal character $ord"; |
1215
|
|
|
|
|
|
|
} |
1216
|
6
|
|
|
|
|
33
|
return sprintf( $format, @bytes ); |
1217
|
|
|
|
|
|
|
} |
1218
|
|
|
|
|
|
|
sub _encode_char { |
1219
|
295
|
|
|
295
|
|
444
|
my $self = shift; |
1220
|
295
|
|
|
|
|
534
|
my $ord = ord shift; |
1221
|
|
|
|
|
|
|
|
1222
|
295
|
|
|
|
|
477
|
my $encode = $self->get('encode'); |
1223
|
295
|
|
100
|
|
|
804
|
my $utf = $encode->{utf} // 0; |
1224
|
295
|
100
|
|
|
|
772
|
if ( defined $encode->{$ord} ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1225
|
153
|
|
|
|
|
552
|
return $encode->{$ord}; |
1226
|
|
|
|
|
|
|
} elsif ( $utf == 8 ) { |
1227
|
6
|
|
|
|
|
16
|
return $self->_encode_ord2utf8( $ord ); |
1228
|
|
|
|
|
|
|
} elsif ( $utf == 16 ) { |
1229
|
6
|
|
|
|
|
14
|
return $self->_encode_ord2utf16( $ord ); |
1230
|
|
|
|
|
|
|
} elsif ( $ord <= 255 ) { |
1231
|
127
|
|
|
|
|
532
|
return sprintf $encode->{byte}, $ord; |
1232
|
|
|
|
|
|
|
} elsif ( $ord <= 65_535 ) { |
1233
|
2
|
|
33
|
|
|
6
|
my $encoding = $encode->{wide} // $encode->{byte}; |
1234
|
2
|
|
|
|
|
11
|
return sprintf $encoding, $ord; |
1235
|
|
|
|
|
|
|
} else { |
1236
|
1
|
|
33
|
|
|
7
|
my $encoding = $encode->{vwide} // $encode->{wide} // $encode->{byte}; |
|
|
|
0
|
|
|
|
|
1237
|
1
|
|
|
|
|
6
|
return sprintf $encoding, $ord; |
1238
|
|
|
|
|
|
|
} |
1239
|
|
|
|
|
|
|
} |
1240
|
|
|
|
|
|
|
|
1241
|
|
|
|
|
|
|
# Find a good character to use for delimiting q or qq. |
1242
|
|
|
|
|
|
|
sub _find_q { |
1243
|
1
|
|
|
1
|
|
3
|
my $self = shift; |
1244
|
1
|
50
|
|
|
|
3
|
local $_ = shift if @_; |
1245
|
|
|
|
|
|
|
|
1246
|
1
|
|
|
|
|
3
|
my %counts; |
1247
|
1
|
|
|
|
|
166
|
$counts{$_}++ foreach /([[:punct:]])/g; |
1248
|
|
|
|
|
|
|
#$counts{$_}++ foreach grep /[[:punct:]]/, split //; |
1249
|
1
|
|
50
|
|
|
15
|
my $qpairs = $self->get('qpairs') || []; |
1250
|
1
|
|
|
|
|
3
|
foreach my $pair (@$qpairs) { |
1251
|
|
|
|
|
|
|
$counts{$pair} |
1252
|
|
|
|
|
|
|
= List::Util::sum 0, |
1253
|
|
|
|
|
|
|
grep defined, |
1254
|
4
|
|
|
|
|
9
|
map { $counts{$_} } |
|
8
|
|
|
|
|
23
|
|
1255
|
|
|
|
|
|
|
split //, $pair; |
1256
|
|
|
|
|
|
|
} |
1257
|
|
|
|
|
|
|
|
1258
|
|
|
|
|
|
|
return List::Util::reduce { |
1259
|
23
|
100
|
50
|
23
|
|
58
|
( ( $counts{$a} //= 0 ) <= ( $counts{$b} //= 0 ) ) ? $a : $b |
|
|
|
50
|
|
|
|
|
1260
|
1
|
|
|
|
|
4
|
} @{ $self->get('qpairs') }, @{ $self->get('qquotes') }; |
|
1
|
|
|
|
|
3
|
|
|
1
|
|
|
|
|
3
|
|
1261
|
|
|
|
|
|
|
} |
1262
|
|
|
|
|
|
|
sub _push_position { |
1263
|
592
|
|
|
592
|
|
914
|
my $self = shift; |
1264
|
592
|
|
|
|
|
813
|
my $position = shift; |
1265
|
592
|
|
50
|
|
|
790
|
push @{ $self->{_position} //= [] }, $position; |
|
592
|
|
|
|
|
1504
|
|
1266
|
592
|
|
|
|
|
1031
|
return $self; |
1267
|
|
|
|
|
|
|
} |
1268
|
|
|
|
|
|
|
sub _pop_position { |
1269
|
590
|
|
|
590
|
|
783
|
my $self = shift; |
1270
|
590
|
|
|
|
|
711
|
return pop @{ $self->{_position} }; |
|
590
|
|
|
|
|
1599
|
|
1271
|
|
|
|
|
|
|
} |
1272
|
|
|
|
|
|
|
sub _cache_position { |
1273
|
142
|
|
|
142
|
|
209
|
my $self = shift; |
1274
|
|
|
|
|
|
|
|
1275
|
142
|
|
33
|
|
|
277
|
my $nest = $self->get('nested') // $self->get('dereference'); |
1276
|
|
|
|
|
|
|
my $pos = List::Util::reduce( |
1277
|
0
|
|
|
0
|
|
0
|
sub { _subst( $nest, referent => $a, place => $b ) }, |
1278
|
142
|
|
100
|
|
|
579
|
@{ $self->{_position} //= [] } |
|
142
|
|
|
|
|
743
|
|
1279
|
|
|
|
|
|
|
); |
1280
|
|
|
|
|
|
|
|
1281
|
142
|
|
|
|
|
554
|
my $var = $self->get('name'); |
1282
|
142
|
50
|
|
|
|
436
|
my $sigil = length $var ? substr $var, 0, 1 : ''; |
1283
|
142
|
50
|
33
|
|
|
587
|
if ( $sigil eq '@' || $sigil eq '%' ) { |
|
|
100
|
|
|
|
|
|
1284
|
0
|
0
|
|
|
|
0
|
if ($pos) { |
1285
|
0
|
|
|
|
|
0
|
$var = sprintf '$%s%s', substr($var, 1), $pos; |
1286
|
|
|
|
|
|
|
} else { |
1287
|
0
|
|
|
|
|
0
|
$var = _subst( $self->get('reference'), $var ); |
1288
|
|
|
|
|
|
|
} |
1289
|
|
|
|
|
|
|
} elsif ($pos) { |
1290
|
32
|
|
33
|
|
|
76
|
$var = _subst( |
1291
|
|
|
|
|
|
|
$self->get('dereference') // $self->get('nested'), |
1292
|
|
|
|
|
|
|
referent => $var, |
1293
|
|
|
|
|
|
|
place => $pos |
1294
|
|
|
|
|
|
|
); |
1295
|
|
|
|
|
|
|
} |
1296
|
142
|
|
|
|
|
3710
|
return $var; |
1297
|
|
|
|
|
|
|
} |
1298
|
|
|
|
|
|
|
|
1299
|
|
|
|
|
|
|
__PACKAGE__->set( |
1300
|
|
|
|
|
|
|
# _caching options |
1301
|
|
|
|
|
|
|
_cache_hit => 0, |
1302
|
|
|
|
|
|
|
); |
1303
|
|
|
|
|
|
|
sub _cache_add { |
1304
|
507
|
|
|
507
|
|
766
|
my $self = shift; |
1305
|
507
|
|
|
|
|
641
|
my $ref = shift; |
1306
|
507
|
|
|
|
|
773
|
my $value = shift; |
1307
|
|
|
|
|
|
|
|
1308
|
507
|
100
|
|
|
|
1383
|
return $self unless my $refaddr = Scalar::Util::refaddr $ref; |
1309
|
110
|
|
50
|
|
|
299
|
my $_cache = $self->{_cache} //= {}; |
1310
|
110
|
|
50
|
|
|
262
|
my $entry = $_cache->{$refaddr} //= [ $self->_cache_position ]; |
1311
|
110
|
50
|
|
|
|
248
|
push @$entry, $value if @$entry == $self->get('_cache_hit'); |
1312
|
|
|
|
|
|
|
|
1313
|
110
|
|
|
|
|
201
|
return $self; |
1314
|
|
|
|
|
|
|
} |
1315
|
|
|
|
|
|
|
sub _cache_get { |
1316
|
548
|
|
|
548
|
|
757
|
my $self = shift; |
1317
|
548
|
|
|
|
|
694
|
my $item = shift; |
1318
|
|
|
|
|
|
|
|
1319
|
548
|
100
|
|
|
|
1890
|
return unless my $refaddr = Scalar::Util::refaddr $item; |
1320
|
|
|
|
|
|
|
|
1321
|
148
|
|
100
|
|
|
485
|
my $_cache = $self->{_cache} //= {}; |
1322
|
148
|
100
|
|
|
|
361
|
if ( my $entry = $_cache->{$refaddr} ) { |
1323
|
6
|
|
|
|
|
14
|
my $repr = $self->get('_cache_hit'); |
1324
|
6
|
|
33
|
|
|
38
|
return $entry->[$repr] |
1325
|
|
|
|
|
|
|
// Carp::croak 'Recursive structures not allowed at ', |
1326
|
|
|
|
|
|
|
$self->_cache_position; |
1327
|
|
|
|
|
|
|
} else { |
1328
|
|
|
|
|
|
|
# Pre-populate the cache, so that we can check for loops |
1329
|
142
|
|
|
|
|
357
|
$_cache->{$refaddr} = [ $self->_cache_position ]; |
1330
|
142
|
|
|
|
|
540
|
return; |
1331
|
|
|
|
|
|
|
} |
1332
|
|
|
|
|
|
|
} |
1333
|
|
|
|
|
|
|
sub _cache_reset { |
1334
|
41
|
|
|
41
|
|
67
|
my $self = shift; |
1335
|
41
|
|
100
|
|
|
64
|
%{ $self->{_cache} //= {} } = (); |
|
41
|
|
|
|
|
176
|
|
1336
|
41
|
|
|
|
|
76
|
return $self; |
1337
|
|
|
|
|
|
|
} |
1338
|
|
|
|
|
|
|
|
1339
|
|
|
|
|
|
|
1; |
1340
|
|
|
|
|
|
|
|
1341
|
|
|
|
|
|
|
__END__ |