line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Text::MicroMason::Base; |
2
|
|
|
|
|
|
|
|
3
|
39
|
|
|
39
|
|
125
|
use strict; |
|
39
|
|
|
|
|
37
|
|
|
39
|
|
|
|
|
1172
|
|
4
|
|
|
|
|
|
|
require Carp; |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
###################################################################### |
7
|
|
|
|
|
|
|
|
8
|
|
|
|
|
|
|
###################################################################### |
9
|
|
|
|
|
|
|
|
10
|
39
|
|
|
39
|
|
14782
|
use Class::MixinFactory -hasafactory; |
|
39
|
|
|
|
|
100470
|
|
|
39
|
|
|
|
|
244
|
|
11
|
|
|
|
|
|
|
for my $factory ( (__PACKAGE__)->mixin_factory ) { |
12
|
|
|
|
|
|
|
$factory->base_class( "Text::MicroMason::Base" ); |
13
|
|
|
|
|
|
|
$factory->mixin_prefix( "Text::MicroMason" ); |
14
|
|
|
|
|
|
|
} |
15
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
###################################################################### |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
###################################################################### |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
sub new { |
21
|
145
|
|
|
145
|
1
|
4651
|
my $callee = shift; |
22
|
145
|
|
|
|
|
126
|
my ( @traits, @attribs ); |
23
|
145
|
|
|
|
|
312
|
while ( scalar @_ ) { |
24
|
247
|
100
|
|
|
|
760
|
if ( $_[0] =~ /^\-(\w+)$/ ) { |
25
|
217
|
|
|
|
|
515
|
push @traits, $1; |
26
|
217
|
|
|
|
|
356
|
shift; |
27
|
|
|
|
|
|
|
} else { |
28
|
30
|
|
|
|
|
72
|
push @attribs, splice(@_, 0, 2); |
29
|
|
|
|
|
|
|
} |
30
|
|
|
|
|
|
|
} |
31
|
145
|
100
|
|
|
|
221
|
if ( scalar @traits ) { |
32
|
135
|
50
|
|
|
|
283
|
die("Adding moxins to an existing class not supported yet!") |
33
|
|
|
|
|
|
|
unless ( $callee eq __PACKAGE__ ); |
34
|
135
|
|
|
|
|
424
|
$callee->class( @traits )->create( @attribs ) |
35
|
|
|
|
|
|
|
} else { |
36
|
10
|
|
|
|
|
23
|
$callee->create( @attribs ) |
37
|
|
|
|
|
|
|
} |
38
|
|
|
|
|
|
|
} |
39
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
###################################################################### |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
# $mason = $class->create( %options ); |
43
|
|
|
|
|
|
|
# $clone = $object->create( %options ); |
44
|
|
|
|
|
|
|
sub create { |
45
|
185
|
|
|
185
|
1
|
6210
|
my $referent = shift; |
46
|
185
|
100
|
|
|
|
324
|
if ( ! ref $referent ) { |
47
|
136
|
|
|
|
|
284
|
bless { $referent->defaults(), @_ }, $referent; |
48
|
|
|
|
|
|
|
} else { |
49
|
49
|
|
|
|
|
71
|
bless { $referent->defaults(), %$referent, @_ }, ref $referent; |
50
|
|
|
|
|
|
|
} |
51
|
|
|
|
|
|
|
} |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
sub defaults { |
54
|
|
|
|
|
|
|
return () |
55
|
185
|
|
|
185
|
1
|
1409
|
} |
56
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
###################################################################### |
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
###################################################################### |
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
# $code_ref = $mason->compile( text => $template, %options ); |
62
|
|
|
|
|
|
|
# $code_ref = $mason->compile( file => $filename, %options ); |
63
|
|
|
|
|
|
|
# $code_ref = $mason->compile( handle => $filehandle, %options ); |
64
|
|
|
|
|
|
|
sub compile { |
65
|
292
|
|
|
292
|
1
|
41885
|
my ( $self, $src_type, $src_data, %options ) = @_; |
66
|
|
|
|
|
|
|
|
67
|
292
|
|
|
|
|
652
|
($self, $src_type, $src_data) = $self->prepare($src_type, $src_data,%options); |
68
|
|
|
|
|
|
|
|
69
|
292
|
|
|
|
|
549
|
my $code = $self->interpret( $src_type, $src_data ); |
70
|
|
|
|
|
|
|
|
71
|
292
|
100
|
|
|
|
521
|
$self->eval_sub( $code ) |
72
|
|
|
|
|
|
|
or $self->croak_msg( "MicroMason compilation failed: $@\n". _number_lines($code)."\n" ); |
73
|
|
|
|
|
|
|
|
74
|
|
|
|
|
|
|
} |
75
|
|
|
|
|
|
|
|
76
|
|
|
|
|
|
|
# Internal helper to number the lines in the compiled template when compilation croaks |
77
|
|
|
|
|
|
|
sub _number_lines { |
78
|
14
|
|
|
14
|
|
979
|
my $code = shift; |
79
|
|
|
|
|
|
|
|
80
|
14
|
|
|
|
|
15
|
my $n = 0; |
81
|
14
|
|
|
|
|
54
|
return join("\n", map { sprintf("%4d %s", $n++, $_) } split(/\n/, $code)). |
|
174
|
|
|
|
|
358
|
|
82
|
|
|
|
|
|
|
"\n** Please use Text::MicroMason->new\(-LineNumbers\) for better diagnostics!"; |
83
|
|
|
|
|
|
|
} |
84
|
|
|
|
|
|
|
|
85
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
###################################################################### |
87
|
|
|
|
|
|
|
|
88
|
|
|
|
|
|
|
# $result = $mason->execute( code => $subref, @arguments ); |
89
|
|
|
|
|
|
|
# $result = $mason->execute( $src_type, $src_data, @arguments ); |
90
|
|
|
|
|
|
|
# $result = $mason->execute( $src_type, $src_data, \%options, @arguments ); |
91
|
|
|
|
|
|
|
sub execute { |
92
|
249
|
|
|
249
|
1
|
150331
|
my $self = shift; |
93
|
4
|
|
|
|
|
4
|
my $sub = ( $_[0] eq 'code' ) ? do { shift; shift } : |
|
4
|
|
|
|
|
10
|
|
94
|
249
|
100
|
|
|
|
857
|
$self->compile( shift, shift, ref($_[0]) ? %{ shift() } : () ) |
|
1
|
100
|
|
|
|
15
|
|
|
|
100
|
|
|
|
|
|
95
|
|
|
|
|
|
|
or $self->croak_msg("MicroMason compilation failed: $@"); |
96
|
242
|
|
|
|
|
3883
|
&$sub( @_ ); |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
###################################################################### |
100
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
###################################################################### |
102
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
# ($self, $src_type, $src_data) = $self->prepare($src_type, $src_data, %options) |
104
|
|
|
|
|
|
|
sub prepare { |
105
|
292
|
|
|
292
|
1
|
1672
|
my ( $self, $src_type, $src_data, %options ) = @_; |
106
|
292
|
100
|
|
|
|
620
|
$self = $self->create( %options ) if ( scalar keys %options ); |
107
|
292
|
|
|
|
|
701
|
return ( $self, $src_type, $src_data ); |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
###################################################################### |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
# $perl_code = $mason->interpret( $src_type, $src_data ); |
113
|
|
|
|
|
|
|
sub interpret { |
114
|
294
|
|
|
294
|
1
|
301
|
my ( $self, $src_type, $src_data ) = @_; |
115
|
294
|
|
|
|
|
475
|
my $template = $self->read( $src_type, $src_data ); |
116
|
294
|
|
|
|
|
573
|
my @tokens = $self->lex( $template ); |
117
|
294
|
|
|
|
|
690
|
my $code = $self->assemble( @tokens ); |
118
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
# Source file and line number |
120
|
294
|
|
|
|
|
777
|
my $source_line = $self->source_file_line_label( $src_type, $src_data ); |
121
|
|
|
|
|
|
|
|
122
|
294
|
|
|
|
|
738
|
return $source_line . "\n" . $code; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
|
125
|
|
|
|
|
|
|
# $line_number_comment = $mason->source_file_line_label( $src_type, $src_data ); |
126
|
|
|
|
|
|
|
sub source_file_line_label { |
127
|
294
|
|
|
294
|
0
|
316
|
my ( $self, $src_type, $src_data ) = @_; |
128
|
|
|
|
|
|
|
|
129
|
294
|
100
|
|
|
|
491
|
if ( $src_type eq 'file' ) { |
130
|
47
|
|
|
|
|
93
|
return qq(# line 1 "$src_data"); |
131
|
|
|
|
|
|
|
} |
132
|
|
|
|
|
|
|
|
133
|
247
|
|
|
|
|
171
|
my @caller; |
134
|
|
|
|
|
|
|
my $call_level; |
135
|
247
|
|
100
|
|
|
175
|
do { @caller = caller( ++ $call_level ) } |
|
828
|
|
|
|
|
6902
|
|
136
|
|
|
|
|
|
|
while ( $caller[0] =~ /^Text::MicroMason/ or $self->isa($caller[0]) ); |
137
|
247
|
|
33
|
|
|
427
|
my $package = ( $caller[1] || $0 ); |
138
|
247
|
|
|
|
|
720
|
qq{# line 1 "text template (compiled at $package line $caller[2])"} |
139
|
|
|
|
|
|
|
} |
140
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
|
142
|
|
|
|
|
|
|
###################################################################### |
143
|
|
|
|
|
|
|
|
144
|
|
|
|
|
|
|
# $code_ref = $mason->eval_sub( $perl_code ); |
145
|
|
|
|
|
|
|
sub eval_sub { |
146
|
291
|
|
|
291
|
1
|
267
|
my $m = shift; |
147
|
|
|
|
|
|
|
package Text::MicroMason::Commands; |
148
|
|
|
|
|
|
|
eval( shift ) |
149
|
291
|
|
|
1
|
|
63889
|
} |
|
1
|
|
|
|
|
4
|
|
|
1
|
|
|
|
|
1
|
|
|
1
|
|
|
|
|
43
|
|
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
###################################################################### |
152
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
###################################################################### |
154
|
|
|
|
|
|
|
|
155
|
|
|
|
|
|
|
# $template = $mason->read( $src_type, $src_data ); |
156
|
|
|
|
|
|
|
sub read { |
157
|
294
|
|
|
294
|
1
|
546
|
my ( $self, $src_type, $src_data ) = @_; |
158
|
|
|
|
|
|
|
|
159
|
294
|
|
|
|
|
372
|
my $src_method = "read_$src_type"; |
160
|
294
|
50
|
|
|
|
1040
|
$self->can($src_method) |
161
|
|
|
|
|
|
|
or $self->croak_msg("Unsupported source type '$src_type'"); |
162
|
294
|
|
|
|
|
507
|
$self->$src_method( $src_data ); |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
|
|
|
|
|
|
# $template = $mason->read_text( $template ); |
166
|
|
|
|
|
|
|
sub read_text { |
167
|
244
|
50
|
|
244
|
1
|
650
|
ref($_[1]) ? $$_[1] : $_[1]; |
168
|
|
|
|
|
|
|
} |
169
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
# $contents = $mason->read_file( $filename ); |
171
|
|
|
|
|
|
|
sub read_file { |
172
|
47
|
|
|
47
|
1
|
748
|
my ( $self, $file ) = @_; |
173
|
47
|
|
|
|
|
81
|
local *FILE; |
174
|
47
|
50
|
|
|
|
1165
|
open FILE, "$file" or $self->croak_msg("MicroMason can't open $file: $!"); |
175
|
47
|
|
|
|
|
147
|
local $/ = undef; |
176
|
47
|
|
|
|
|
573
|
local $_ = ; |
177
|
47
|
50
|
|
|
|
304
|
close FILE or $self->croak_msg("MicroMason can't close $file: $!");; |
178
|
47
|
|
|
|
|
253
|
return $_; |
179
|
|
|
|
|
|
|
} |
180
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
# $contents = $mason->read_handle( $filehandle ); |
182
|
|
|
|
|
|
|
sub read_handle { |
183
|
3
|
|
|
3
|
1
|
4
|
my ( $self, $handle ) = @_; |
184
|
3
|
50
|
|
|
|
10
|
my $fh = (ref $handle eq 'GLOB') ? $handle : $$handle; |
185
|
3
|
|
|
|
|
8
|
local $/ = undef; |
186
|
|
|
|
|
|
|
<$fh> |
187
|
3
|
|
|
|
|
53
|
} |
188
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
###################################################################### |
190
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
# @token_pairs = $mason->lex( $template ); |
192
|
|
|
|
|
|
|
sub lex { |
193
|
280
|
|
|
280
|
1
|
257
|
my $self = shift; |
194
|
280
|
|
|
|
|
391
|
local $_ = "$_[0]"; |
195
|
280
|
|
|
|
|
217
|
my @tokens; |
196
|
280
|
50
|
|
|
|
725
|
my $lexer = $self->can('lex_token') |
197
|
|
|
|
|
|
|
or $self->croak_msg('Unable to lex_token(); must select a syntax mixin'); |
198
|
|
|
|
|
|
|
# warn "Lexing: " . pos($_) . " of " . length($_) . "\n"; |
199
|
280
|
|
|
|
|
753
|
until ( /\G\z/gc ) { |
200
|
1118
|
50
|
0
|
|
|
1694
|
my @parsed = &$lexer( $self ) or |
201
|
|
|
|
|
|
|
/\G ( .{0,20} ) /gcxs |
202
|
|
|
|
|
|
|
&& die "MicroMason parsing halted at '$1'\n"; |
203
|
1118
|
|
|
|
|
2773
|
push @tokens, @parsed; |
204
|
|
|
|
|
|
|
} |
205
|
280
|
|
|
|
|
882
|
return @tokens; |
206
|
|
|
|
|
|
|
} |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# ( $type, $value ) = $mason->lex_token(); |
209
|
|
|
|
|
|
|
sub lex_token { |
210
|
0
|
|
|
0
|
1
|
0
|
die "The lex_token() method is abstract and must be provided by a subclass"; |
211
|
|
|
|
|
|
|
} |
212
|
|
|
|
|
|
|
|
213
|
|
|
|
|
|
|
###################################################################### |
214
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
###################################################################### |
216
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
# Text elements used for subroutine assembly |
218
|
|
|
|
|
|
|
sub assembler_rules { |
219
|
|
|
|
|
|
|
template => [ qw( $sub_start $init_errs $init_output |
220
|
|
|
|
|
|
|
$init_args @perl $return_output $sub_end ) ], |
221
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
# Subroutine scafolding |
223
|
|
|
|
|
|
|
sub_start => 'sub { ', |
224
|
|
|
|
|
|
|
sub_end => '}', |
225
|
|
|
|
|
|
|
init_errs => |
226
|
|
|
|
|
|
|
'local $SIG{__DIE__} = sub { die "MicroMason execution failed: ", @_ };', |
227
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
# Argument processing elements |
229
|
|
|
|
|
|
|
init_args => 'my %ARGS = @_ if ($#_ % 2);', |
230
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# Output generation |
232
|
289
|
50
|
|
289
|
|
230
|
init_output => sub { my $m = shift; my $sub = $m->{output_sub} ? '$m->{output_sub}' : 'sub {push @OUT, @_}'; 'my @OUT; my $_out = ' . $sub . ';' }, |
|
289
|
|
|
|
|
425
|
|
|
289
|
|
|
|
|
773
|
|
233
|
289
|
50
|
|
289
|
|
222
|
add_output => sub { my $m = shift; $m->{output_sub} ? '&$_out' : 'push @OUT,' }, |
|
289
|
|
|
|
|
746
|
|
234
|
294
|
|
|
294
|
1
|
9100
|
return_output => 'join("", @OUT)', |
235
|
|
|
|
|
|
|
|
236
|
|
|
|
|
|
|
# Mapping between token types |
237
|
|
|
|
|
|
|
text_token => 'perl OUT( QUOTED );', |
238
|
|
|
|
|
|
|
expr_token => "perl OUT( \"\".do{\nTOKEN\n} );", |
239
|
|
|
|
|
|
|
# the "". here forces string context, and should hopefully make |
240
|
|
|
|
|
|
|
# 'uninitialized' warnings appear closer to their source, rather |
241
|
|
|
|
|
|
|
# than at the big join "", @OUT; at the end |
242
|
|
|
|
|
|
|
file_token => "perl OUT( \$m->execute( file => do {\nTOKEN\n} ) );", |
243
|
|
|
|
|
|
|
# Note that we need newline after TOKEN here in case it ends with a comment. |
244
|
|
|
|
|
|
|
} |
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub assembler_vars { |
247
|
294
|
|
|
294
|
0
|
224
|
my $self = shift; |
248
|
294
|
|
|
|
|
558
|
my %assembler = $self->assembler_rules(); |
249
|
|
|
|
|
|
|
|
250
|
294
|
|
|
|
|
543
|
my @assembly = @{ delete $assembler{ template } }; |
|
294
|
|
|
|
|
719
|
|
251
|
|
|
|
|
|
|
|
252
|
990
|
|
|
|
|
2725
|
my %token_map = map { ( /^(.*?)_token$/ )[0] => delete $assembler{$_} } |
253
|
294
|
|
|
|
|
762
|
grep { /_token$/ } keys %assembler; |
|
3076
|
|
|
|
|
3555
|
|
254
|
|
|
|
|
|
|
|
255
|
294
|
100
|
|
|
|
684
|
my %fragments = map { $_ => map { ref($_) ? &{$_}( $self ) : $_ } $assembler{$_} } keys %assembler; |
|
2086
|
|
|
|
|
1567
|
|
|
2086
|
|
|
|
|
2978
|
|
|
578
|
|
|
|
|
764
|
|
256
|
|
|
|
|
|
|
|
257
|
294
|
|
|
|
|
1474
|
return( \@assembly, \%fragments, \%token_map ); |
258
|
|
|
|
|
|
|
} |
259
|
|
|
|
|
|
|
|
260
|
|
|
|
|
|
|
# $perl_code = $mason->assemble( @tokens ); |
261
|
|
|
|
|
|
|
sub assemble { |
262
|
294
|
|
|
294
|
1
|
1506
|
my $self = shift; |
263
|
294
|
|
|
|
|
497
|
my @tokens = @_; |
264
|
|
|
|
|
|
|
|
265
|
294
|
|
|
|
|
476
|
my ( $order, $fragments, $token_map ) = $self->assembler_vars(); |
266
|
|
|
|
|
|
|
|
267
|
294
|
|
|
|
|
382
|
my %token_streams = map { $_ => [] } map { ( /^\W?\@(\w+)$/ ) } @$order; |
|
1402
|
|
|
|
|
1782
|
|
|
3194
|
|
|
|
|
3572
|
|
268
|
|
|
|
|
|
|
|
269
|
294
|
|
|
|
|
798
|
while ( scalar @tokens ) { |
270
|
1185
|
|
|
|
|
1359
|
my ( $type, $token ) = splice( @tokens, 0, 2 ); |
271
|
|
|
|
|
|
|
|
272
|
1185
|
100
|
66
|
|
|
2566
|
unless ( $token_streams{$type} or $token_map->{$type} ) { |
273
|
39
|
|
|
|
|
49
|
my $method = "assemble_$type"; |
274
|
39
|
50
|
|
|
|
122
|
my $sub = $self->can( $method ) |
275
|
|
|
|
|
|
|
or $self->croak_msg( "Unexpected token type '$type': '$token'" ); |
276
|
39
|
|
|
|
|
70
|
($type, $token) = &$sub( $self, $token ); |
277
|
|
|
|
|
|
|
} |
278
|
|
|
|
|
|
|
|
279
|
1185
|
100
|
|
|
|
1734
|
if ( my $typedef = $token_map->{ $type } ) { |
280
|
|
|
|
|
|
|
# Perform token map substitution in a single pass so that uses of |
281
|
|
|
|
|
|
|
# OUT in the token text are not improperly converted to output calls. |
282
|
|
|
|
|
|
|
# -- Simon, 2009-11-14 |
283
|
|
|
|
|
|
|
my %substitution_map = ( |
284
|
|
|
|
|
|
|
'OUT' => $fragments->{add_output}, |
285
|
917
|
|
|
|
|
2302
|
'TOKEN' => $token, |
286
|
|
|
|
|
|
|
'QUOTED' => "qq(\Q$token\E)", |
287
|
|
|
|
|
|
|
); |
288
|
917
|
|
|
|
|
4789
|
$typedef =~ s/\b(OUT|TOKEN|QUOTED)\b/$substitution_map{$1}/g; |
289
|
|
|
|
|
|
|
|
290
|
917
|
|
|
|
|
1965
|
( $type, $token ) = split ' ', $typedef, 2; |
291
|
|
|
|
|
|
|
} |
292
|
|
|
|
|
|
|
|
293
|
1185
|
50
|
|
|
|
1828
|
my $ary = $token_streams{$type} |
294
|
|
|
|
|
|
|
or $self->croak_msg( "Unexpected token type '$type': '$token'" ); |
295
|
|
|
|
|
|
|
|
296
|
1185
|
|
|
|
|
2296
|
push @$ary, $token |
297
|
|
|
|
|
|
|
} |
298
|
|
|
|
|
|
|
|
299
|
|
|
|
|
|
|
join( "\n", map { |
300
|
294
|
50
|
|
|
|
360
|
/^(\W+)(\w+)$/ or $self->croak_msg("Can't assemble $_"); |
|
3194
|
|
|
|
|
5439
|
|
301
|
3194
|
100
|
|
|
|
4653
|
if ( $1 eq '$' ) { |
|
|
100
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
302
|
1792
|
|
|
|
|
2169
|
$fragments->{ $2 } |
303
|
|
|
|
|
|
|
} elsif ( $1 eq '@' ) { |
304
|
848
|
|
|
|
|
529
|
@{ $token_streams{ $2 } } |
|
848
|
|
|
|
|
1390
|
|
305
|
|
|
|
|
|
|
} elsif ( $1 eq '!@' ) { |
306
|
277
|
|
|
|
|
181
|
reverse @{ $token_streams{ $2 } } |
|
277
|
|
|
|
|
426
|
|
307
|
|
|
|
|
|
|
} elsif ( $1 eq '-@' ) { |
308
|
|
|
|
|
|
|
() |
309
|
277
|
|
|
|
|
1716
|
} else { |
310
|
0
|
|
|
|
|
0
|
$self->croak_msg("Can't assemble $_"); |
311
|
|
|
|
|
|
|
} |
312
|
|
|
|
|
|
|
} @$order ); |
313
|
|
|
|
|
|
|
} |
314
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
###################################################################### |
316
|
|
|
|
|
|
|
|
317
|
|
|
|
|
|
|
###################################################################### |
318
|
|
|
|
|
|
|
|
319
|
|
|
|
|
|
|
sub croak_msg { |
320
|
16
|
|
|
16
|
1
|
17
|
local $Carp::CarpLevel = 2; |
321
|
16
|
50
|
|
|
|
2764
|
shift and Carp::croak( ( @_ == 1 ) ? $_[0] : join(' ', map _printable(), @_) ) |
|
|
50
|
|
|
|
|
|
322
|
|
|
|
|
|
|
} |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
my %Escape = ( |
325
|
|
|
|
|
|
|
( map { chr($_), unpack('H2', chr($_)) } (0..255) ), |
326
|
|
|
|
|
|
|
"\\"=>'\\', "\r"=>'r', "\n"=>'n', "\t"=>'t', "\""=>'"' |
327
|
|
|
|
|
|
|
); |
328
|
|
|
|
|
|
|
|
329
|
|
|
|
|
|
|
# $special_characters_escaped = _printable( $source_string ); |
330
|
|
|
|
|
|
|
sub _printable { |
331
|
0
|
0
|
|
0
|
|
0
|
local $_ = scalar(@_) ? (shift) : $_; |
332
|
0
|
0
|
|
|
|
0
|
return "(undef)" unless defined; |
333
|
0
|
|
|
|
|
0
|
s/([\r\n\t\"\\\x00-\x1f\x7F-\xFF])/\\$Escape{$1}/sgo; |
334
|
0
|
0
|
|
|
|
0
|
/[^\w\d\-\:\.\']/ ? "q($_)" : $_; |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
###################################################################### |
338
|
|
|
|
|
|
|
|
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
sub cache_key { |
341
|
52
|
|
|
52
|
0
|
83
|
my $self = shift; |
342
|
52
|
|
|
|
|
49
|
my ($src_type, $src_data, %options) = @_; |
343
|
|
|
|
|
|
|
|
344
|
52
|
|
|
|
|
80
|
return $src_data; |
345
|
|
|
|
|
|
|
} |
346
|
|
|
|
|
|
|
|
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
1; |
349
|
|
|
|
|
|
|
|
350
|
|
|
|
|
|
|
__END__ |