| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Hades; |
|
2
|
|
|
|
|
|
|
|
|
3
|
13
|
|
|
13
|
|
952787
|
use 5.006; |
|
|
13
|
|
|
|
|
154
|
|
|
4
|
13
|
|
|
13
|
|
100
|
use strict; |
|
|
13
|
|
|
|
|
43
|
|
|
|
13
|
|
|
|
|
431
|
|
|
5
|
13
|
|
|
13
|
|
85
|
use warnings; |
|
|
13
|
|
|
|
|
24
|
|
|
|
13
|
|
|
|
|
693
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.20'; |
|
7
|
13
|
|
|
13
|
|
7776
|
use Module::Generate; |
|
|
13
|
|
|
|
|
4629104
|
|
|
|
13
|
|
|
|
|
593
|
|
|
8
|
13
|
|
|
13
|
|
8123
|
use Switch::Again qw/switch/; |
|
|
13
|
|
|
|
|
270361
|
|
|
|
13
|
|
|
|
|
119
|
|
|
9
|
13
|
|
|
13
|
|
7950
|
use Hades::Myths { as_keywords => 1 }; |
|
|
13
|
|
|
|
|
44
|
|
|
|
13
|
|
|
|
|
102
|
|
|
10
|
|
|
|
|
|
|
|
|
11
|
|
|
|
|
|
|
our ($PARENTHESES, $PARSE_PARAM_STRING); |
|
12
|
|
|
|
|
|
|
BEGIN { |
|
13
|
13
|
|
|
13
|
|
123
|
$PARENTHESES = qr{ \( ( (?: (?> [^()]+ ) | (??{ $PARENTHESES }) )* ) \) }x; |
|
14
|
13
|
|
|
|
|
200386
|
$PARSE_PARAM_STRING = qr{ (^ (?: (?> [^(),]+ ) | (??{ $PARENTHESES }) )* ) \, }x; |
|
15
|
|
|
|
|
|
|
} |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
sub new { |
|
18
|
19
|
100
|
|
19
|
0
|
31806
|
my ($class, %args) = (shift, scalar @_ == 1 ? %{$_[0]} : @_); |
|
|
11
|
|
|
|
|
68
|
|
|
19
|
19
|
50
|
|
|
|
93
|
$args{macros} = {} if !$args{macros}; |
|
20
|
19
|
50
|
|
|
|
67
|
eval qq|require "Data::Dumper"| if $args{debug}; |
|
21
|
19
|
|
|
|
|
67
|
bless \%args, $class; |
|
22
|
|
|
|
|
|
|
} |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
sub verbose { |
|
25
|
908
|
|
|
908
|
1
|
1393
|
my ($self, $verbose) = @_; |
|
26
|
908
|
50
|
|
|
|
1666
|
if (defined $verbose) { |
|
27
|
0
|
|
|
|
|
0
|
$self->{verbose} = !!$verbose; |
|
28
|
|
|
|
|
|
|
} |
|
29
|
908
|
|
|
|
|
10761
|
return $self->{verbose}; |
|
30
|
|
|
|
|
|
|
} |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
sub debug { |
|
33
|
908
|
|
|
908
|
1
|
1334
|
my ($self, $debug) = @_; |
|
34
|
908
|
50
|
|
|
|
1600
|
if (defined $debug) { |
|
35
|
0
|
|
|
|
|
0
|
$self->{debug} = !!$debug; |
|
36
|
|
|
|
|
|
|
} |
|
37
|
908
|
|
|
|
|
2468
|
return $self->{debug}; |
|
38
|
|
|
|
|
|
|
} |
|
39
|
|
|
|
|
|
|
|
|
40
|
|
|
|
|
|
|
sub debug_step { |
|
41
|
908
|
|
|
908
|
0
|
1885
|
my ($self, $message, @debug) = @_; |
|
42
|
908
|
50
|
33
|
|
|
1689
|
if ($self->debug || $self->verbose) { |
|
43
|
0
|
|
|
|
|
0
|
$self->{debug_step}++; |
|
44
|
0
|
|
|
|
|
0
|
my @caller = caller(); |
|
45
|
0
|
|
|
|
|
0
|
print "hades step $self->{debug_step} line $caller[2]: $message\n"; |
|
46
|
0
|
0
|
|
|
|
0
|
if ($self->debug) { |
|
47
|
0
|
|
|
|
|
0
|
print Data::Dumper::Dumper $_ for (@debug); |
|
48
|
0
|
|
|
|
|
0
|
print press_enter_to_continue . "\n"; |
|
49
|
0
|
|
|
|
|
0
|
my $ahh = <STDIN>; |
|
50
|
|
|
|
|
|
|
} |
|
51
|
|
|
|
|
|
|
} |
|
52
|
|
|
|
|
|
|
} |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
sub run { |
|
55
|
12
|
|
|
12
|
1
|
198910
|
my ($class, $args) = @_; |
|
56
|
12
|
50
|
|
|
|
77
|
$args->{eval} = _read_file($args->{file}) if $args->{file}; |
|
57
|
12
|
|
|
|
|
132
|
my $mg = Module::Generate->start; |
|
58
|
12
|
|
66
|
|
|
263
|
$args->{$_} && $mg->$_($args->{$_}) for (qw/dist lib tlib author email version/); |
|
59
|
12
|
100
|
|
|
|
235
|
if ($args->{realm}) { |
|
60
|
1
|
|
|
|
|
6
|
$class = sprintf "Hades::Realm::%s", $args->{realm}; |
|
61
|
1
|
|
|
|
|
70
|
eval "require $class"; |
|
62
|
|
|
|
|
|
|
} |
|
63
|
12
|
|
|
|
|
1519
|
my $self = $class->new($args); |
|
64
|
12
|
|
|
|
|
77
|
$self->debug_step(sprintf(debug_step_1, $class), $args); |
|
65
|
12
|
100
|
|
|
|
115
|
$self->can('module_generate') && $self->module_generate($mg, $class); |
|
66
|
12
|
|
|
|
|
174
|
$self->debug_step(sprintf(debug_step_2, $class), $args->{eval}); |
|
67
|
12
|
|
|
|
|
40
|
my ($index, $ident, @lines, @line, @innerline, $nested) = (0, ''); |
|
68
|
12
|
|
|
|
|
113
|
while ($index <= length $self->{eval}) { |
|
69
|
7344
|
|
|
|
|
12964
|
my $first_char = $self->index($index++); |
|
70
|
|
|
|
|
|
|
$ident =~ m/^((:.*\()|(\{)|(\[))/ |
|
71
|
|
|
|
|
|
|
? do { |
|
72
|
5374
|
|
|
|
|
7063
|
my $copy = $ident; |
|
73
|
5374
|
|
|
|
|
8236
|
$copy =~ s/\\\{|\\\}|\\\(|\\\)|\\\[|\\\]//g; # remove escaped |
|
74
|
5374
|
|
|
|
|
62079
|
1 while ($copy =~ s/\([^()]*\)|\{[^{}]*\}|\[[^\[\]]*\]//g); |
|
75
|
|
|
|
|
|
|
($copy =~ m/\(|\{|\[|\)|\}|\]/) ? do { |
|
76
|
5249
|
|
|
|
|
13525
|
$ident .= $first_char; |
|
77
|
5374
|
100
|
|
|
|
13808
|
} : do { |
|
78
|
125
|
50
|
|
|
|
260
|
if ($nested) { |
|
79
|
125
|
|
|
|
|
268
|
push @innerline, $ident; |
|
80
|
|
|
|
|
|
|
} else { |
|
81
|
0
|
|
|
|
|
0
|
push @line, $ident; |
|
82
|
|
|
|
|
|
|
} |
|
83
|
125
|
|
|
|
|
305
|
$ident = ''; |
|
84
|
|
|
|
|
|
|
} |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
: ($first_char =~ m/\s/ && $ident !~ m/^$/) |
|
87
|
|
|
|
|
|
|
? (($nested) |
|
88
|
|
|
|
|
|
|
? ($ident =~ m/^(:|\$|\%|\@|\&)/) ? do { |
|
89
|
|
|
|
|
|
|
push @innerline, $ident; |
|
90
|
|
|
|
|
|
|
} : do { |
|
91
|
|
|
|
|
|
|
push @line, [@innerline] if scalar @innerline; |
|
92
|
|
|
|
|
|
|
@innerline = ($ident); |
|
93
|
|
|
|
|
|
|
} |
|
94
|
|
|
|
|
|
|
: do { |
|
95
|
|
|
|
|
|
|
push @line, $ident; |
|
96
|
|
|
|
|
|
|
}) && do { $ident = '' } |
|
97
|
|
|
|
|
|
|
: ($first_char =~ m/\{/) |
|
98
|
|
|
|
|
|
|
? ! $nested ? $nested++ : do { |
|
99
|
31
|
50
|
|
|
|
92
|
push @innerline, $ident if $ident; |
|
100
|
31
|
|
|
|
|
77
|
$ident = '{'; |
|
101
|
|
|
|
|
|
|
} |
|
102
|
|
|
|
|
|
|
: ($first_char =~ m/\}/ && do { $nested--; 1; }) |
|
103
|
|
|
|
|
|
|
? do{ |
|
104
|
17
|
50
|
|
|
|
113
|
push @line, [@innerline] if @innerline; |
|
105
|
17
|
50
|
|
|
|
163
|
push @lines, [@line] if @line; |
|
106
|
17
|
|
|
|
|
75
|
(@innerline, @line) = ((), ()); |
|
107
|
|
|
|
|
|
|
} |
|
108
|
7344
|
100
|
100
|
|
|
24005
|
: do { |
|
|
|
100
|
33
|
|
|
|
|
|
|
|
100
|
66
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
109
|
1748
|
100
|
|
|
|
4569
|
$ident .= $first_char unless $first_char =~ m/\s/; |
|
110
|
|
|
|
|
|
|
}; |
|
111
|
|
|
|
|
|
|
} |
|
112
|
12
|
50
|
|
|
|
52
|
if (scalar @lines) { |
|
113
|
12
|
|
|
|
|
221
|
$self->debug_step(sprintf(debug_step_3, scalar @lines), \@lines); |
|
114
|
12
|
|
|
|
|
26
|
my $last_token; |
|
115
|
12
|
|
|
|
|
35
|
for my $class (@lines) { |
|
116
|
17
|
50
|
|
|
|
203
|
$self->can('before_class') && $self->before_class($mg, $class); |
|
117
|
17
|
|
|
|
|
88
|
my $meta = {}; |
|
118
|
17
|
|
|
|
|
38
|
for my $token (@{$self->build_class($mg, $class)}) { |
|
|
17
|
|
|
|
|
88
|
|
|
119
|
80
|
|
|
|
|
314
|
$self->debug_step(debug_step_13, $token); |
|
120
|
|
|
|
|
|
|
! ref $token |
|
121
|
8
|
|
|
|
|
34
|
? do { $last_token = $self->build_class_inheritance($mg, $last_token, $token); } |
|
122
|
72
|
|
|
|
|
1047
|
: scalar @{$token} == 1 |
|
123
|
|
|
|
|
|
|
? $self->build_accessor_no_arguments($mg, $token, $meta) |
|
124
|
|
|
|
|
|
|
: $token->[0] =~ m/^(synopsis|abstract|test)$/ |
|
125
|
80
|
50
|
|
|
|
250
|
? do { my $m = "build_$1"; $self->$m($mg, $token, $meta); } |
|
|
3
|
100
|
|
|
|
12
|
|
|
|
3
|
100
|
|
|
|
20
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
: $token->[1] =~ s/^{|}$//g |
|
127
|
|
|
|
|
|
|
? $self->build_sub_no_arguments($mg, $token, $meta) |
|
128
|
|
|
|
|
|
|
: $token->[0] =~ m/^(our)$/ |
|
129
|
|
|
|
|
|
|
? $self->build_our($mg, $token, $meta) |
|
130
|
|
|
|
|
|
|
: $self->build_sub_or_accessor($mg, $token, $meta); |
|
131
|
|
|
|
|
|
|
} |
|
132
|
17
|
100
|
|
|
|
46
|
if (scalar keys %{$meta}) { |
|
|
17
|
|
|
|
|
142
|
|
|
133
|
15
|
|
|
|
|
97
|
$self->build_new($mg, $meta); |
|
134
|
15
|
100
|
|
|
|
166
|
$self->can('after_class') && $self->after_class($mg, $meta); |
|
135
|
15
|
|
|
|
|
368
|
$self->debug_step(debug_step_35, $meta); |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
} |
|
138
|
12
|
|
|
|
|
56
|
$self->debug_step(debug_step_36); |
|
139
|
|
|
|
|
|
|
} |
|
140
|
12
|
50
|
|
|
|
105
|
$self->can('before_generate') && $self->before_generate($mg); |
|
141
|
12
|
|
|
|
|
61
|
$self->debug_step(debug_step_37); |
|
142
|
12
|
|
|
|
|
76
|
$mg->generate; |
|
143
|
12
|
50
|
|
|
|
69170146
|
$self->can('after_generate') && $self->after_generate($mg); |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
sub build_class { |
|
147
|
17
|
|
|
17
|
0
|
56
|
my ($self, $mg, $class) = @_; |
|
148
|
17
|
|
|
|
|
186
|
while ($class->[0] =~ m/^(dist|lib|tlib|realm|author|email|version)$/) { |
|
149
|
0
|
|
|
|
|
0
|
$mg->$1($class->[1]); |
|
150
|
0
|
|
|
|
|
0
|
$self->debug_step(sprintf(debug_step_4, $1, $class->[1])); |
|
151
|
0
|
|
|
|
|
0
|
shift @{$class}, shift @{$class}; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
152
|
|
|
|
|
|
|
} |
|
153
|
17
|
100
|
|
|
|
120
|
if ($class->[0] eq 'macro') { |
|
154
|
2
|
|
|
|
|
4
|
shift @{$class}; |
|
|
2
|
|
|
|
|
5
|
|
|
155
|
2
|
|
|
|
|
11
|
$self->debug_step(debug_step_5, $class); |
|
156
|
2
|
|
|
|
|
9
|
$self->build_macro($mg, $class); |
|
157
|
2
|
|
|
|
|
10
|
return []; |
|
158
|
|
|
|
|
|
|
} |
|
159
|
15
|
|
|
|
|
73
|
$self->debug_step(sprintf (debug_step_12, $class->[0]), $class); |
|
160
|
15
|
|
|
|
|
36
|
$mg->class(shift @{$class})->new; |
|
|
15
|
|
|
|
|
113
|
|
|
161
|
15
|
|
|
|
|
3496
|
return $class; |
|
162
|
|
|
|
|
|
|
} |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
sub build_new { |
|
165
|
15
|
|
|
15
|
0
|
142
|
my ($self, $mg, $meta) = @_; |
|
166
|
15
|
|
|
|
|
108
|
my %class = %Module::Generate::CLASS; |
|
167
|
15
|
|
|
|
|
79
|
$self->debug_step(sprintf (debug_step_33, $class{CURRENT}{NAME}), $meta); |
|
168
|
15
|
|
|
|
|
40
|
my $accessors = q|(|; |
|
169
|
|
|
|
|
|
|
map { |
|
170
|
46
|
|
|
|
|
90
|
$accessors .= qq|$_ => {|; |
|
171
|
46
|
100
|
|
|
|
116
|
$accessors .= qq|required => 1,| if $meta->{$_}->{required}; |
|
172
|
46
|
100
|
|
|
|
119
|
$accessors .= qq|default => $meta->{$_}->{default},| if $meta->{$_}->{default}; |
|
173
|
|
|
|
|
|
|
$accessors .= qq|builder => sub { my (\$self, \$value) = \@_;| . $self->build_builder($_, '$value', $meta->{$_}->{builder}) . qq|return \$value;}| |
|
174
|
46
|
100
|
|
|
|
95
|
if $meta->{$_}->{builder}; |
|
175
|
46
|
|
|
|
|
86
|
$accessors .= qq|},|; |
|
176
|
15
|
|
|
|
|
32
|
} grep { $meta->{$_}->{meta} eq 'ACCESSOR' } keys %{$meta}; |
|
|
69
|
|
|
|
|
168
|
|
|
|
15
|
|
|
|
|
58
|
|
|
177
|
15
|
|
|
|
|
40
|
$accessors .= q|)|; |
|
178
|
15
|
100
|
100
|
|
|
106
|
my $new = $class{CURRENT}->{PARENT} || $class{CURRENT}->{BASE} ? 'my $self = $cls->SUPER::new(%args)' : 'my $self = bless {}, $cls'; |
|
179
|
15
|
|
|
|
|
74
|
my $code = qq|{ |
|
180
|
|
|
|
|
|
|
my (\$cls, \%args) = (shift(), scalar \@_ == 1 ? \%{\$_[0]} : \@_); |
|
181
|
|
|
|
|
|
|
$new; |
|
182
|
|
|
|
|
|
|
my \%accessors = $accessors; |
|
183
|
|
|
|
|
|
|
for my \$accessor ( keys \%accessors ) { |
|
184
|
|
|
|
|
|
|
my \$param = defined \$args{\$accessor} ? \$args{\$accessor} : \$accessors{\$accessor}->{default}; |
|
185
|
|
|
|
|
|
|
my \$value = \$self->\$accessor( |
|
186
|
|
|
|
|
|
|
\$accessors{\$accessor}->{builder} ? \$accessors{\$accessor}->{builder}->( |
|
187
|
|
|
|
|
|
|
\$self, |
|
188
|
|
|
|
|
|
|
\$param |
|
189
|
|
|
|
|
|
|
) : \$param |
|
190
|
|
|
|
|
|
|
); |
|
191
|
|
|
|
|
|
|
unless (!\$accessors{\$accessor}->{required} \|\| defined \$value) { |
|
192
|
|
|
|
|
|
|
die "\$accessor accessor is required"; |
|
193
|
|
|
|
|
|
|
} |
|
194
|
|
|
|
|
|
|
} |
|
195
|
|
|
|
|
|
|
return \$self; |
|
196
|
|
|
|
|
|
|
}|; |
|
197
|
15
|
|
|
|
|
50
|
$class{CURRENT}{SUBS}{new}{CODE} = $code; |
|
198
|
15
|
|
|
|
|
303
|
$class{CURRENT}{SUBS}{new}{TEST} = [$self->build_tests('new', $meta, 'new', \%class)]; |
|
199
|
15
|
|
|
|
|
166
|
$self->debug_step(sprintf (debug_step_34, $class{CURRENT}{NAME}), $code); |
|
200
|
|
|
|
|
|
|
} |
|
201
|
|
|
|
|
|
|
|
|
202
|
|
|
|
|
|
|
sub build_class_inheritance { |
|
203
|
8
|
|
|
8
|
0
|
21
|
my ($self, $mg, $last_token, $token) = @_; |
|
204
|
|
|
|
|
|
|
($token =~ m/^(parent|base|require|use)$/) ? do { |
|
205
|
4
|
|
|
|
|
19
|
$self->debug_step(sprintf(debug_step_14, $token), sprintf(debug_step_14_b, $token)); |
|
206
|
4
|
|
|
|
|
12
|
$last_token = $token; |
|
207
|
8
|
100
|
|
|
|
47
|
} : do { |
|
208
|
4
|
|
|
|
|
15
|
$self->debug_step(sprintf(debug_step_15, $last_token, $token)); |
|
209
|
4
|
|
|
|
|
55
|
$mg->$last_token($token); |
|
210
|
|
|
|
|
|
|
}; |
|
211
|
8
|
|
|
|
|
70
|
return $last_token; |
|
212
|
|
|
|
|
|
|
} |
|
213
|
|
|
|
|
|
|
|
|
214
|
|
|
|
|
|
|
sub build_accessor_no_arguments { |
|
215
|
0
|
|
|
0
|
0
|
0
|
my ($self, $mg, $token, $meta) = @_; |
|
216
|
0
|
|
|
|
|
0
|
$meta->{$token->[0]}->{meta} = 'ACCESSOR'; |
|
217
|
0
|
|
|
|
|
0
|
$self->debug_step(sprintf(debug_step_16, $token->[0]), $meta->{$token->[0]}); |
|
218
|
0
|
|
|
|
|
0
|
$mg->accessor($token->[0]); |
|
219
|
0
|
|
|
|
|
0
|
return $meta; |
|
220
|
|
|
|
|
|
|
} |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
sub build_sub_no_arguments { |
|
223
|
3
|
|
|
3
|
0
|
11
|
my ($self, $mg, $token, $meta) = @_; |
|
224
|
3
|
|
|
|
|
6
|
my $name = shift @{$token}; |
|
|
3
|
|
|
|
|
8
|
|
|
225
|
3
|
|
|
|
|
11
|
$self->debug_step(sprintf(debug_step_18, $name), $meta->{$name}); |
|
226
|
|
|
|
|
|
|
$name =~ m/^(begin|unitcheck|check|init|end|new)$/ |
|
227
|
0
|
|
|
|
|
0
|
? $mg->$name('{' . join( ' ', @{$token}) . '}') |
|
228
|
3
|
50
|
|
|
|
26
|
: $mg->sub($name)->code($self->build_code($mg, $name, $self->build_sub_code($name, '', '', join ' ', @{$token}))) |
|
|
3
|
|
|
|
|
56
|
|
|
229
|
|
|
|
|
|
|
->pod(qq|call $name method. Expects no params.|)->example(qq|\$obj->$name()|); |
|
230
|
3
|
|
|
|
|
71
|
return $meta; |
|
231
|
|
|
|
|
|
|
} |
|
232
|
|
|
|
|
|
|
|
|
233
|
|
|
|
|
|
|
sub build_our { |
|
234
|
0
|
|
|
0
|
0
|
0
|
my ($self, $mg, $token, $meta) = @_; |
|
235
|
0
|
|
|
|
|
0
|
my $name = shift @{$token}; |
|
|
0
|
|
|
|
|
0
|
|
|
236
|
0
|
|
|
|
|
0
|
$self->debug_step(debug_step_19, $token); |
|
237
|
0
|
|
|
|
|
0
|
$mg->$name( '(' . join( ', ', @{$token}) . ')'); |
|
|
0
|
|
|
|
|
0
|
|
|
238
|
0
|
|
|
|
|
0
|
return $meta; |
|
239
|
|
|
|
|
|
|
} |
|
240
|
|
|
|
|
|
|
|
|
241
|
1
|
|
|
1
|
0
|
7
|
sub build_synopsis { goto &build_synopsis_or_abstract; } |
|
242
|
|
|
|
|
|
|
|
|
243
|
1
|
|
|
1
|
0
|
4
|
sub build_abstract { goto &build_synopsis_or_abstract; } |
|
244
|
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
sub build_test { |
|
246
|
1
|
|
|
1
|
0
|
3
|
my ($self, $mg, $token, $meta) = @_; |
|
247
|
1
|
|
|
|
|
3
|
my ($name, $content) = @{$token}; |
|
|
1
|
|
|
|
|
4
|
|
|
248
|
1
|
|
|
|
|
6
|
$self->debug_step(sprintf(debug_step_17, $name), $content); |
|
249
|
1
|
|
|
|
|
69
|
$content =~ s/^\{\s*|\s*\}$//g; |
|
250
|
1
|
|
|
|
|
132
|
$mg->class_tests(eval $content); |
|
251
|
1
|
|
|
|
|
16
|
return $meta; |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
|
|
254
|
|
|
|
|
|
|
sub build_synopsis_or_abstract { |
|
255
|
2
|
|
|
2
|
0
|
6
|
my ($self, $mg, $token, $meta) = @_; |
|
256
|
2
|
|
|
|
|
3
|
my ($name, $content) = @{$token}; |
|
|
2
|
|
|
|
|
5
|
|
|
257
|
2
|
|
|
|
|
7
|
$self->debug_step(sprintf(debug_step_17, $name), $content); |
|
258
|
2
|
|
|
|
|
32
|
$content =~ s/^\{\s*|\s*\}$//g; |
|
259
|
2
|
|
|
|
|
12
|
$mg->$name($content); |
|
260
|
2
|
|
|
|
|
15
|
return $meta; |
|
261
|
|
|
|
|
|
|
} |
|
262
|
|
|
|
|
|
|
|
|
263
|
|
|
|
|
|
|
sub build_sub_or_accessor_attributes { |
|
264
|
69
|
|
|
69
|
0
|
189
|
my ($self, $name, $token, $meta) = @_; |
|
265
|
|
|
|
|
|
|
my @ATTR = ( |
|
266
|
|
|
|
|
|
|
'default' => sub { |
|
267
|
0
|
|
|
0
|
|
0
|
my $value = shift; |
|
268
|
0
|
|
|
|
|
0
|
push @{$meta->{$name}->{caught}}, $value; |
|
|
0
|
|
|
|
|
0
|
|
|
269
|
|
|
|
|
|
|
}, |
|
270
|
|
|
|
|
|
|
qr/^(\:around|\:ar)$/ => sub { |
|
271
|
1
|
|
|
1
|
|
23
|
$meta->{$name}->{meta} = 'MODIFY'; |
|
272
|
1
|
|
|
|
|
45
|
$token->[-1] =~ s/^\{(.*)\}$/$1/sg; |
|
273
|
1
|
|
|
|
|
5
|
$meta->{$name}->{around} = pop @{$token}; |
|
|
1
|
|
|
|
|
6
|
|
|
274
|
|
|
|
|
|
|
}, |
|
275
|
|
|
|
|
|
|
qr/^(\:after|\:a)$/ => sub { |
|
276
|
2
|
|
|
2
|
|
59
|
$meta->{$name}->{meta} = 'MODIFY'; |
|
277
|
2
|
|
|
|
|
19
|
$token->[-1] =~ s/^\{(.*)\}$/$1/sg; |
|
278
|
2
|
|
|
|
|
3
|
$meta->{$name}->{after} = pop @{$token}; |
|
|
2
|
|
|
|
|
9
|
|
|
279
|
|
|
|
|
|
|
}, |
|
280
|
|
|
|
|
|
|
qr/^(\:before|\:b)$/ => sub { |
|
281
|
0
|
|
|
0
|
|
0
|
$meta->{$name}->{meta} = 'MODIFY'; |
|
282
|
0
|
|
|
|
|
0
|
$token->[-1] =~ s/^\{(.*)\}$/$1/sg; |
|
283
|
0
|
|
|
|
|
0
|
$meta->{$name}->{before} = pop @{$token}; |
|
|
0
|
|
|
|
|
0
|
|
|
284
|
|
|
|
|
|
|
}, |
|
285
|
|
|
|
|
|
|
qr/^(:builder|:bdr)/ => sub { |
|
286
|
1
|
|
|
1
|
|
34
|
my $value = shift; |
|
287
|
1
|
|
|
|
|
3
|
$value =~ s/(\:bd|\:build)\((.*)\)$/$2/sg; |
|
288
|
1
|
50
|
|
|
|
7
|
$meta->{$name}->{builder} = $2 ? $value : 1; |
|
289
|
|
|
|
|
|
|
}, |
|
290
|
|
|
|
|
|
|
qr/^(\:clearer|\:c)$/ => sub { |
|
291
|
12
|
|
|
12
|
|
515
|
$meta->{$name}->{clearer} = 1; |
|
292
|
|
|
|
|
|
|
}, |
|
293
|
|
|
|
|
|
|
qr/^(\:coerce|\:co)/ => sub { |
|
294
|
2
|
|
|
2
|
|
89
|
my $value = shift; |
|
295
|
2
|
|
|
|
|
12
|
$value =~ s/(\:co|\:coerce)\((.*)\)$/$2/sg; |
|
296
|
2
|
|
|
|
|
4
|
$meta->{$name}->{coerce} = $value; |
|
297
|
2
|
100
|
|
|
|
9
|
if ($meta->{$name}->{params_map}) { |
|
298
|
|
|
|
|
|
|
$meta->{$name}->{params_map}->{ |
|
299
|
|
|
|
|
|
|
$meta->{$name}->{param}->[-1] |
|
300
|
1
|
|
|
|
|
5
|
}->{coerce} = $value; |
|
301
|
|
|
|
|
|
|
} |
|
302
|
|
|
|
|
|
|
}, |
|
303
|
|
|
|
|
|
|
qr/^(\:default|\:d)/ => sub { |
|
304
|
22
|
|
|
22
|
|
1279
|
my $value = shift; |
|
305
|
22
|
|
|
|
|
156
|
$value =~ s/.*\((.*)\)/$1/sg; |
|
306
|
22
|
100
|
|
|
|
121
|
$value = '"' . $value . '"' |
|
307
|
|
|
|
|
|
|
if $value !~ m/^(\{|\[|\"|\'|\$|\£|q)|(\d+)/; |
|
308
|
22
|
|
|
|
|
56
|
$meta->{$name}->{default} = $value; |
|
309
|
22
|
100
|
|
|
|
105
|
if ($meta->{$name}->{params_map}) { |
|
310
|
|
|
|
|
|
|
$meta->{$name}->{params_map}->{ |
|
311
|
|
|
|
|
|
|
$meta->{$name}->{param}->[-1] |
|
312
|
5
|
|
|
|
|
28
|
}->{default} = $value; |
|
313
|
|
|
|
|
|
|
} |
|
314
|
|
|
|
|
|
|
}, |
|
315
|
|
|
|
|
|
|
qr/^(\:example)/ => sub { |
|
316
|
2
|
|
|
2
|
|
107
|
my $value = shift; |
|
317
|
2
|
|
|
|
|
18
|
$value =~ s/^\:example\(\s*(.*)\s*\)$/$1/sg; |
|
318
|
2
|
|
|
|
|
10
|
$meta->{$name}->{example} = $value; |
|
319
|
|
|
|
|
|
|
}, |
|
320
|
|
|
|
|
|
|
qr/^(\:no_success_test)/ => sub { |
|
321
|
0
|
|
|
0
|
|
0
|
$meta->{$name}->{no_success_test} = 1; |
|
322
|
|
|
|
|
|
|
}, |
|
323
|
|
|
|
|
|
|
qr/^(\:pod)/ => sub { |
|
324
|
2
|
|
|
2
|
|
132
|
my $value = shift; |
|
325
|
2
|
|
|
|
|
11
|
$value =~ s/^:pod\(\s*(.*)\s*\)$/$1/sg; |
|
326
|
2
|
|
|
|
|
9
|
$meta->{$name}->{pod} = $value; |
|
327
|
|
|
|
|
|
|
}, |
|
328
|
|
|
|
|
|
|
qr/^(\:private|\:p)$/ => sub { |
|
329
|
7
|
|
|
7
|
|
511
|
$meta->{$name}->{private} = 1; |
|
330
|
|
|
|
|
|
|
}, |
|
331
|
|
|
|
|
|
|
qr/^(\:predicate|\:pr)$/ => sub { |
|
332
|
9
|
|
|
9
|
|
742
|
$meta->{$name}->{predicate} = 1; |
|
333
|
|
|
|
|
|
|
}, |
|
334
|
|
|
|
|
|
|
qr/^(\:required|\:r)$/ => sub { |
|
335
|
12
|
|
|
12
|
|
1103
|
$meta->{$name}->{required} = 1; |
|
336
|
|
|
|
|
|
|
}, |
|
337
|
|
|
|
|
|
|
qr/^(\:trigger|\:tr)/ => sub { |
|
338
|
2
|
|
|
2
|
|
173
|
my $value = shift; |
|
339
|
2
|
|
|
|
|
11
|
$value =~ s/(\:tr|\:trigger)\((.*)\)$/$2/sg; |
|
340
|
2
|
|
|
|
|
9
|
$meta->{$name}->{trigger} = $value; |
|
341
|
|
|
|
|
|
|
}, |
|
342
|
|
|
|
|
|
|
qr/^(\:test|\z)/ => sub { |
|
343
|
2
|
|
|
2
|
|
185
|
my $value = shift; |
|
344
|
2
|
|
|
|
|
17
|
$value =~ s/^(\:test|\:z)\(\s*(.*)\s*\)$/$2/sg; |
|
345
|
2
|
|
|
|
|
4
|
push @{$meta->{$name}->{test}}, eval '(' . $value . ')'; |
|
|
2
|
|
|
|
|
192
|
|
|
346
|
|
|
|
|
|
|
}, |
|
347
|
|
|
|
|
|
|
qr/^(\:type|\:t)/ => sub { |
|
348
|
62
|
|
|
62
|
|
6388
|
my $value = shift; |
|
349
|
62
|
|
|
|
|
401
|
$value =~ s/.*\((.*)\)/$1/sg; |
|
350
|
62
|
|
|
|
|
113
|
push @{$meta->{$name}->{type}}, $value; |
|
|
62
|
|
|
|
|
224
|
|
|
351
|
62
|
100
|
|
|
|
280
|
if ($meta->{$name}->{params_map}) { |
|
352
|
|
|
|
|
|
|
$meta->{$name}->{params_map}->{ |
|
353
|
|
|
|
|
|
|
$meta->{$name}->{param}->[-1] |
|
354
|
21
|
|
|
|
|
187
|
}->{type} = $value; |
|
355
|
|
|
|
|
|
|
} |
|
356
|
|
|
|
|
|
|
}, |
|
357
|
|
|
|
|
|
|
qr/^(\{)/ => sub { |
|
358
|
20
|
|
|
20
|
|
2061
|
my $value = shift; |
|
359
|
20
|
|
|
|
|
309
|
$value =~ s/^\{|\}$//g; |
|
360
|
20
|
50
|
|
|
|
86
|
$meta->{$name}->{meta} = 'METHOD' unless $meta->{$name}->{meta} eq 'MODIFY'; |
|
361
|
20
|
|
|
|
|
82
|
$meta->{$name}->{code} = $value; |
|
362
|
|
|
|
|
|
|
}, |
|
363
|
|
|
|
|
|
|
qr/^(\%|\$|\@|\&)/ => sub { |
|
364
|
26
|
|
|
26
|
|
3041
|
push @{$meta->{$name}->{param}}, $_[0]; |
|
|
26
|
|
|
|
|
84
|
|
|
365
|
26
|
|
|
|
|
112
|
$meta->{$name}->{params_map}->{$_[0]} = {}; |
|
366
|
|
|
|
|
|
|
} |
|
367
|
69
|
|
|
|
|
3159
|
); |
|
368
|
69
|
|
|
|
|
508
|
return @ATTR; |
|
369
|
|
|
|
|
|
|
} |
|
370
|
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
sub build_sub_or_accessor { |
|
372
|
72
|
|
|
72
|
0
|
212
|
my ($self, $mg, $token, $meta) = @_; |
|
373
|
72
|
|
|
|
|
115
|
my $name = shift @{$token}; |
|
|
72
|
|
|
|
|
159
|
|
|
374
|
72
|
100
|
|
|
|
283
|
if ($name =~ s/^\[(.*)\]$/$1/) { |
|
375
|
3
|
|
|
|
|
13
|
$self->debug_step(debug_step_20, $1); |
|
376
|
3
|
|
|
|
|
14
|
$self->build_sub_or_accessor($mg, [$_, @{$token}], $meta) for split / /, $1; |
|
|
6
|
|
|
|
|
54
|
|
|
377
|
3
|
|
|
|
|
17
|
return; |
|
378
|
|
|
|
|
|
|
} |
|
379
|
69
|
|
|
|
|
220
|
$self->debug_step(sprintf(debug_step_21, $name), $token); |
|
380
|
69
|
|
|
|
|
276
|
$meta->{$name}->{meta} = 'ACCESSOR'; |
|
381
|
69
|
|
|
|
|
274
|
my $switch = switch( |
|
382
|
|
|
|
|
|
|
$self->build_sub_or_accessor_attributes($name, $token, $meta) |
|
383
|
|
|
|
|
|
|
); |
|
384
|
69
|
|
|
|
|
8905
|
$switch->(shift @{$token}) while scalar @{$token}; |
|
|
253
|
|
|
|
|
1314
|
|
|
|
184
|
|
|
|
|
408
|
|
|
385
|
69
|
|
|
|
|
289
|
$self->debug_step(sprintf(debug_step_22, $name), $meta->{$name}); |
|
386
|
|
|
|
|
|
|
$meta->{$name}->{meta} eq 'ACCESSOR' |
|
387
|
|
|
|
|
|
|
? $self->build_accessor($mg, $name, $meta) |
|
388
|
69
|
100
|
|
|
|
447
|
: $meta->{$name}->{meta} eq 'MODIFY' |
|
|
|
100
|
|
|
|
|
|
|
389
|
|
|
|
|
|
|
? $self->build_modify($mg, $name, $meta) |
|
390
|
|
|
|
|
|
|
: $self->build_sub($mg, $name, $meta); |
|
391
|
69
|
100
|
|
|
|
373
|
$self->build_predicate($mg, $name, $meta) if $meta->{$name}->{predicate}; |
|
392
|
69
|
100
|
|
|
|
244
|
$self->build_clearer($mg, $name, $meta) if $meta->{$name}->{clearer}; |
|
393
|
69
|
|
|
|
|
3971
|
return $meta; |
|
394
|
|
|
|
|
|
|
} |
|
395
|
|
|
|
|
|
|
|
|
396
|
|
|
|
|
|
|
sub build_accessor { |
|
397
|
44
|
|
|
44
|
0
|
187
|
my ($self, $mg, $name, $meta) = @_; |
|
398
|
44
|
|
|
|
|
166
|
$self->debug_step(sprintf(debug_step_23, $name), $meta->{$name}); |
|
399
|
44
|
|
|
|
|
237
|
my $private = $self->build_private($name, $meta->{$name}->{private}); |
|
400
|
|
|
|
|
|
|
my $type = $self->build_coerce($name, '$value', $meta->{$name}->{coerce}) |
|
401
|
44
|
|
|
|
|
247
|
. $self->build_type($name, $meta->{$name}->{type}[0]); |
|
402
|
44
|
|
|
|
|
354
|
my $trigger = $self->build_trigger($name, '$value', $meta->{$name}->{trigger}); |
|
403
|
44
|
|
|
|
|
603
|
my $code = $self->build_code($mg, $name, $self->build_accessor_code($name, $private, $type, $trigger)); |
|
404
|
44
|
|
|
|
|
287
|
$mg->accessor($name)->code($code)->clear_tests->test($self->build_tests($name, $meta->{$name})); |
|
405
|
44
|
|
66
|
|
|
760
|
$meta->{$name}->{$_} && $mg->$_($self->replace_pe_string($meta->{$name}->{$_}, $name)) for qw/pod example/; |
|
406
|
44
|
|
|
|
|
222
|
$self->debug_step(sprintf(debug_step_28, $name), $meta->{$name}); |
|
407
|
|
|
|
|
|
|
} |
|
408
|
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
sub build_accessor_code { |
|
410
|
44
|
|
|
44
|
0
|
142
|
my ($self, $name, $private, $type, $trigger) = @_; |
|
411
|
44
|
|
|
|
|
401
|
return qq|{ |
|
412
|
|
|
|
|
|
|
my ( \$self, \$value ) = \@_; $private |
|
413
|
|
|
|
|
|
|
if ( defined \$value ) { $type |
|
414
|
|
|
|
|
|
|
\$self->{$name} = \$value; $trigger |
|
415
|
|
|
|
|
|
|
} |
|
416
|
|
|
|
|
|
|
return \$self->{$name}; |
|
417
|
|
|
|
|
|
|
}|; |
|
418
|
|
|
|
|
|
|
} |
|
419
|
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
sub replace_pe_string { |
|
421
|
4
|
|
|
4
|
0
|
25
|
my ($self, $str, $name) = @_; |
|
422
|
4
|
|
|
|
|
16
|
$str =~ s/\$name/$name/g; |
|
423
|
4
|
|
|
|
|
21
|
return $str; |
|
424
|
|
|
|
|
|
|
} |
|
425
|
|
|
|
|
|
|
|
|
426
|
|
|
|
|
|
|
sub build_modify { |
|
427
|
3
|
|
|
3
|
0
|
11
|
my ($self, $mg, $name, $meta) = @_; |
|
428
|
3
|
|
|
|
|
10
|
$self->debug_step(sprintf(debug_step_29, $name), $meta->{$name}); |
|
429
|
3
|
|
50
|
|
|
17
|
my $before_code = $meta->{$name}->{before} || ""; |
|
430
|
3
|
|
100
|
|
|
12
|
my $around_code = $meta->{$name}->{around} || qq|my \@res = \$self->\$orig(\@params);|; |
|
431
|
3
|
|
100
|
|
|
11
|
my $after_code = $meta->{$name}->{after} || ""; |
|
432
|
3
|
|
|
|
|
13
|
my $code = $self->build_code($mg, $name, $self->build_modify_code($name, $before_code, $around_code, $after_code)); |
|
433
|
3
|
|
|
|
|
16
|
$mg->sub($name)->code($code)->pod(qq|call $name method.|)->test($self->build_tests($name, $meta->{$name})); |
|
434
|
3
|
|
33
|
|
|
34
|
$meta->{$name}->{$_} && $mg->$_($self->replace_pe_string($meta->{$name}->{$_}, $name)) for qw/pod example/; |
|
435
|
3
|
|
|
|
|
11
|
$self->debug_step(sprintf(debug_step_30, $name), $meta->{$name}); |
|
436
|
|
|
|
|
|
|
} |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
sub build_modify_code { |
|
439
|
3
|
|
|
3
|
0
|
8
|
my ($self, $name, $before_code, $around_code, $after_code) =@_; |
|
440
|
3
|
|
|
|
|
34
|
return qq|{ |
|
441
|
|
|
|
|
|
|
my (\$orig, \$self, \@params) = ('SUPER::$name', \@_); |
|
442
|
|
|
|
|
|
|
$before_code$around_code$after_code |
|
443
|
|
|
|
|
|
|
return wantarray ? \@res : \$res[0]; |
|
444
|
|
|
|
|
|
|
}|; |
|
445
|
|
|
|
|
|
|
} |
|
446
|
|
|
|
|
|
|
|
|
447
|
|
|
|
|
|
|
sub build_sub { |
|
448
|
20
|
|
|
20
|
0
|
65
|
my ($self, $mg, $name, $meta) = @_; |
|
449
|
20
|
|
|
|
|
44
|
my $code = $meta->{$name}->{code}; |
|
450
|
20
|
|
|
|
|
72
|
$self->debug_step(sprintf(debug_step_31, $name), $meta->{$name}); |
|
451
|
20
|
|
|
|
|
58
|
my ($params, $subtype, $params_explanation) = ( '', '', '' ); |
|
452
|
|
|
|
|
|
|
$subtype .= $self->build_private($name) |
|
453
|
20
|
50
|
|
|
|
81
|
if $meta->{$name}->{private}; |
|
454
|
20
|
50
|
|
|
|
72
|
if ($meta->{$name}->{param}) { |
|
455
|
20
|
|
|
|
|
46
|
for my $param (@{ $meta->{$name}->{param} }) { |
|
|
20
|
|
|
|
|
65
|
|
|
456
|
26
|
100
|
|
|
|
62
|
$params_explanation .= ', ' if $params_explanation; |
|
457
|
26
|
|
|
|
|
58
|
$params .= ', ' . $param; |
|
458
|
26
|
|
|
|
|
86
|
my $pm = $meta->{$name}->{params_map}->{$param}; |
|
459
|
|
|
|
|
|
|
$subtype .= qq|$param = defined $param ? $param : $pm->{default};| |
|
460
|
26
|
100
|
|
|
|
82
|
if ($pm->{default}); |
|
461
|
26
|
|
|
|
|
147
|
$subtype .= $self->build_coerce($name, $param, $pm->{coerce}); |
|
462
|
26
|
100
|
|
|
|
85
|
if ($pm->{type}) { |
|
463
|
21
|
50
|
|
|
|
221
|
my $error_message = ($pm->{type} !~ m/^(Optional|Any|Item)/ |
|
464
|
|
|
|
|
|
|
? qq|$param = defined $param ? $param : 'undef';| : q||) |
|
465
|
|
|
|
|
|
|
. qq|die qq{$pm->{type}: invalid value $param for variable \\$param in method $name};|; |
|
466
|
|
|
|
|
|
|
$subtype .= $self->build_type( |
|
467
|
|
|
|
|
|
|
$name, |
|
468
|
|
|
|
|
|
|
$pm->{type}, |
|
469
|
|
|
|
|
|
|
$param, |
|
470
|
|
|
|
|
|
|
$error_message, |
|
471
|
21
|
50
|
|
|
|
159
|
($pm->{type} !~ m/^(Optional|Any|Item)/ |
|
472
|
|
|
|
|
|
|
? qq|! defined($param) \|\|| : q||) |
|
473
|
|
|
|
|
|
|
); |
|
474
|
21
|
|
|
|
|
129
|
$params_explanation .= qq|param $param to be a $pm->{type}|; |
|
475
|
|
|
|
|
|
|
} else { |
|
476
|
5
|
|
|
|
|
19
|
$params_explanation .= qq|param $param to be any value including undef|; |
|
477
|
|
|
|
|
|
|
} |
|
478
|
|
|
|
|
|
|
} |
|
479
|
|
|
|
|
|
|
} |
|
480
|
20
|
|
|
|
|
64
|
$meta->{$name}->{params_explanation} = $params_explanation; |
|
481
|
20
|
|
|
|
|
148
|
$code = $self->build_code($mg, $name, $self->build_sub_code($name, $params, $subtype, $code)); |
|
482
|
20
|
|
|
|
|
108
|
$params =~ s/^,\s*//; |
|
483
|
20
|
|
|
|
|
74
|
my $example = qq|\$obj->$name($params)|; |
|
484
|
|
|
|
|
|
|
$mg->sub($name)->code($code) |
|
485
|
|
|
|
|
|
|
->pod(qq|call $name method. Expects $params_explanation.|) |
|
486
|
|
|
|
|
|
|
->example($example) |
|
487
|
20
|
|
|
|
|
103
|
->test($self->build_tests($name, $meta->{$name})); |
|
488
|
20
|
|
66
|
|
|
327
|
$meta->{$name}->{$_} && $mg->$_($self->replace_pe_string($meta->{$name}->{$_}, $name)) for qw/pod example/; |
|
489
|
20
|
|
|
|
|
84
|
$self->debug_step(sprintf(debug_step_32, $name), $meta->{$name}); |
|
490
|
|
|
|
|
|
|
} |
|
491
|
|
|
|
|
|
|
|
|
492
|
|
|
|
|
|
|
sub build_code { |
|
493
|
91
|
|
|
91
|
0
|
262
|
my ($self, $mg, $name, $code) = @_; |
|
494
|
91
|
|
|
|
|
301
|
$self->debug_step(sprintf(debug_step_38, $name), $code); |
|
495
|
91
|
50
|
|
|
|
248
|
return unless defined $code; |
|
496
|
91
|
|
|
|
|
4268
|
1 while $code =~ s/€(\w+(|$PARENTHESES));/$self->build_macro_code($mg, $1)/ge; |
|
|
10
|
|
|
|
|
34
|
|
|
497
|
91
|
|
|
|
|
349
|
$code =~ s/£(\w*(\s|\$|\-|\;|\,|\{|\}|\[|\]|\)|\(|\:))/$self->build_self($1)/eg; |
|
|
9
|
|
|
|
|
28
|
|
|
498
|
91
|
|
|
|
|
299
|
$self->debug_step(sprintf(debug_step_44, $name), $code); |
|
499
|
91
|
|
|
|
|
266
|
return $code; |
|
500
|
|
|
|
|
|
|
} |
|
501
|
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
sub build_self { |
|
503
|
9
|
|
|
9
|
0
|
30
|
my ($self, $name) = @_; |
|
504
|
9
|
|
|
|
|
49
|
return qq|\$self->$name|; |
|
505
|
|
|
|
|
|
|
} |
|
506
|
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
sub parse_params { |
|
508
|
10
|
|
|
10
|
0
|
28
|
my ($self, $param_string) = @_; |
|
509
|
10
|
|
|
|
|
17
|
my @params; |
|
510
|
10
|
|
|
|
|
64
|
while ($param_string =~ s/$PARSE_PARAM_STRING//g) { |
|
511
|
8
|
|
|
|
|
23
|
push @params, $self->minimise_param_string($1); |
|
512
|
|
|
|
|
|
|
} |
|
513
|
10
|
|
|
|
|
37
|
push @params, $self->minimise_param_string($param_string); |
|
514
|
10
|
|
|
|
|
102
|
return @params; |
|
515
|
|
|
|
|
|
|
} |
|
516
|
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
sub minimise_param_string { |
|
518
|
18
|
|
|
18
|
0
|
37
|
my ($self, $string) = @_; |
|
519
|
18
|
50
|
|
|
|
40
|
return $string unless length $string; |
|
520
|
18
|
|
|
|
|
32
|
$string =~ s/^\s*\(\s*(.*)\s*\)\s*$/$1/sg; |
|
521
|
18
|
|
|
|
|
72
|
$string =~ s/\s+/ /g; |
|
522
|
18
|
|
|
|
|
124
|
$string =~ s/^\s*|\s*$//g; |
|
523
|
18
|
|
|
|
|
114
|
$string =~ s/^q*(("|'|\||\/))((\\{2})*|(.*?[^\\](\\{2})*))\1$/$3/sg; # back compat |
|
524
|
18
|
|
|
|
|
55
|
$string =~ s/q+(\{|\})((\\[\{\}])*|(.*?[^\\]([\{\}])*))\}/$2/sg; # back compat |
|
525
|
18
|
50
|
|
|
|
44
|
return undef if $string =~ m/^undef$/; |
|
526
|
18
|
|
|
|
|
55
|
return $string; |
|
527
|
|
|
|
|
|
|
} |
|
528
|
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
sub build_macro_code { |
|
530
|
10
|
|
|
10
|
0
|
73
|
my ($self, $mg, $match) = @_; |
|
531
|
10
|
|
|
|
|
30
|
$self->debug_step(sprintf(debug_step_39, $match)); |
|
532
|
10
|
50
|
|
|
|
316
|
if ($match =~ m/^(.*)$PARENTHESES$/m) { |
|
533
|
10
|
|
|
|
|
30
|
$self->debug_step(sprintf(debug_step_40, $1), $2); |
|
534
|
10
|
50
|
|
|
|
55
|
return '' unless $self->{macros}->{$1}->{code}; |
|
535
|
10
|
|
|
|
|
24
|
$self->debug_step(sprintf(debug_step_41, $1), $self->{macros}->{$1}->{code}); |
|
536
|
10
|
|
|
|
|
29
|
my $v = $self->{macros}->{$1}->{code}->($self, $mg, $self->parse_params($2)); |
|
537
|
10
|
|
|
|
|
33
|
$self->debug_step(sprintf(debug_step_42, $1), $v); |
|
538
|
10
|
|
|
|
|
274
|
return $v; |
|
539
|
|
|
|
|
|
|
} |
|
540
|
0
|
0
|
|
|
|
0
|
return '' unless $self->{macros}->{$match}->{code}; |
|
541
|
0
|
|
|
|
|
0
|
$self->debug_step(sprintf(debug_step_43, $match), $self->{macros}->{$match}->{code}); |
|
542
|
0
|
|
|
|
|
0
|
my $v = $self->{macros}->{$match}->{code}->($self, $mg); |
|
543
|
0
|
|
|
|
|
0
|
$self->debug_step(sprintf(debug_step_42, $match), $v); |
|
544
|
0
|
|
|
|
|
0
|
return $v; |
|
545
|
|
|
|
|
|
|
} |
|
546
|
|
|
|
|
|
|
|
|
547
|
|
|
|
|
|
|
sub build_sub_code { |
|
548
|
23
|
|
|
23
|
0
|
72
|
my ($self, $name, $params, $subtype, $code) = @_; |
|
549
|
23
|
|
|
|
|
145
|
return qq|{ |
|
550
|
|
|
|
|
|
|
my (\$self $params) = \@_; $subtype |
|
551
|
|
|
|
|
|
|
$code; |
|
552
|
|
|
|
|
|
|
}|; |
|
553
|
|
|
|
|
|
|
} |
|
554
|
|
|
|
|
|
|
|
|
555
|
|
|
|
|
|
|
sub build_clearer { |
|
556
|
12
|
|
|
12
|
0
|
48
|
my ($self, $mg, $name, $meta) = @_; |
|
557
|
12
|
|
|
|
|
42
|
$self->debug_step(sprintf(debug_step_47, $name)); |
|
558
|
|
|
|
|
|
|
$mg->sub(qq|clear_$name|) |
|
559
|
|
|
|
|
|
|
->code($self->build_code($mg, $name, $self->build_clearer_code($name))) |
|
560
|
|
|
|
|
|
|
->pod(qq|clear $name accessor|) |
|
561
|
|
|
|
|
|
|
->example(qq|\$obj->clear_$name|) |
|
562
|
|
|
|
|
|
|
->test( |
|
563
|
12
|
|
|
|
|
69
|
$self->build_tests($name, $meta->{$name}, "success"), |
|
564
|
|
|
|
|
|
|
['ok', qq|\$obj->clear_$name|], |
|
565
|
|
|
|
|
|
|
['is', qq|\$obj->$name|, 'undef'] |
|
566
|
|
|
|
|
|
|
); |
|
567
|
12
|
|
|
|
|
150
|
$self->debug_step(sprintf(debug_step_48, $name)); |
|
568
|
12
|
|
|
|
|
29
|
return ($mg, $name, $meta); |
|
569
|
|
|
|
|
|
|
} |
|
570
|
|
|
|
|
|
|
|
|
571
|
|
|
|
|
|
|
sub build_clearer_code { |
|
572
|
12
|
|
|
12
|
0
|
206
|
my ($self, $name) = @_; |
|
573
|
12
|
|
|
|
|
48
|
return qq|{ |
|
574
|
|
|
|
|
|
|
my (\$self) = \@_; |
|
575
|
|
|
|
|
|
|
delete \$self->{$name}; |
|
576
|
|
|
|
|
|
|
return \$self; |
|
577
|
|
|
|
|
|
|
}|; |
|
578
|
|
|
|
|
|
|
} |
|
579
|
|
|
|
|
|
|
|
|
580
|
|
|
|
|
|
|
sub build_predicate { |
|
581
|
9
|
|
|
9
|
0
|
37
|
my ($self, $mg, $name, $meta) = @_; |
|
582
|
9
|
|
|
|
|
34
|
$self->debug_step(sprintf(debug_step_45, $name)); |
|
583
|
|
|
|
|
|
|
$mg->sub(qq|has_$name|) |
|
584
|
|
|
|
|
|
|
->code($self->build_code($mg, $name, $self->build_predicate_code($name))) |
|
585
|
|
|
|
|
|
|
->pod(qq|has_$name will return true if $name accessor has a value.|) |
|
586
|
|
|
|
|
|
|
->example(qq|\$obj->has_$name|) |
|
587
|
|
|
|
|
|
|
->test( |
|
588
|
|
|
|
|
|
|
['ok', qq|do{ delete \$obj->{$name}; 1;}|], |
|
589
|
|
|
|
|
|
|
['is', qq|\$obj->has_$name|, q|''|], |
|
590
|
9
|
|
|
|
|
47
|
$self->build_tests($name, $meta->{$name}, 'success'), |
|
591
|
|
|
|
|
|
|
['is', qq|\$obj->has_$name|, 1], |
|
592
|
|
|
|
|
|
|
); |
|
593
|
9
|
|
|
|
|
107
|
$self->debug_step(sprintf(debug_step_46, $name)); |
|
594
|
9
|
|
|
|
|
20
|
return ($mg, $name, $meta); |
|
595
|
|
|
|
|
|
|
} |
|
596
|
|
|
|
|
|
|
|
|
597
|
|
|
|
|
|
|
sub build_predicate_code { |
|
598
|
9
|
|
|
9
|
0
|
155
|
my ($self, $name) = @_; |
|
599
|
9
|
|
|
|
|
44
|
return qq|{ |
|
600
|
|
|
|
|
|
|
my (\$self) = \@_; |
|
601
|
|
|
|
|
|
|
return exists \$self->{$name}; |
|
602
|
|
|
|
|
|
|
}|; |
|
603
|
|
|
|
|
|
|
} |
|
604
|
|
|
|
|
|
|
|
|
605
|
|
|
|
|
|
|
sub build_builder { |
|
606
|
1
|
|
|
1
|
0
|
3
|
my ($self, $name, $param, $code) = @_; |
|
607
|
1
|
50
|
|
|
|
4
|
if (defined $code) { |
|
608
|
1
|
50
|
|
|
|
6
|
$code = "_build_$name" if $code =~ m/^1$/; |
|
609
|
1
|
50
|
|
|
|
11
|
return $code =~ m/^\w+$/ |
|
610
|
|
|
|
|
|
|
? qq|$param = \$self->$code($param);| |
|
611
|
|
|
|
|
|
|
: $code |
|
612
|
|
|
|
|
|
|
} |
|
613
|
0
|
|
|
|
|
0
|
return q||; |
|
614
|
|
|
|
|
|
|
} |
|
615
|
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
sub build_coerce { |
|
617
|
70
|
|
|
70
|
0
|
271
|
my ($self, $name, $param, $code) = @_; |
|
618
|
70
|
100
|
|
|
|
217
|
if (defined $code) { |
|
619
|
2
|
50
|
|
|
|
15
|
$code = $code =~ m/^\w+$/ |
|
620
|
|
|
|
|
|
|
? qq|$param = \$self->$code($param);| |
|
621
|
|
|
|
|
|
|
: $code; |
|
622
|
2
|
|
|
|
|
7
|
$self->debug_step(sprintf(debug_step_25, $name), $code); |
|
623
|
2
|
|
|
|
|
8
|
return $code; |
|
624
|
|
|
|
|
|
|
} |
|
625
|
68
|
|
|
|
|
247
|
return q||; |
|
626
|
|
|
|
|
|
|
} |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
sub build_trigger { |
|
629
|
44
|
|
|
44
|
0
|
217
|
my ($self, $name, $param, $code) = @_; |
|
630
|
|
|
|
|
|
|
|
|
631
|
44
|
100
|
|
|
|
142
|
if (defined $code) { |
|
632
|
1
|
50
|
|
|
|
10
|
$code = $code =~ m/^1$/ |
|
|
|
50
|
|
|
|
|
|
|
633
|
|
|
|
|
|
|
? qq|\$self->_trigger_$name| |
|
634
|
|
|
|
|
|
|
: $code =~ m/^\w+$/ |
|
635
|
|
|
|
|
|
|
? qq|\$self->$code($param);| |
|
636
|
|
|
|
|
|
|
: $code; |
|
637
|
1
|
|
|
|
|
3
|
$self->debug_step(sprintf(debug_step_27, $name), $code); |
|
638
|
1
|
|
|
|
|
3
|
return $code; |
|
639
|
|
|
|
|
|
|
} |
|
640
|
43
|
|
|
|
|
117
|
return q||; |
|
641
|
|
|
|
|
|
|
} |
|
642
|
|
|
|
|
|
|
|
|
643
|
|
|
|
|
|
|
sub build_private { |
|
644
|
44
|
|
|
44
|
0
|
259
|
my ($self, $name, $private) = @_; |
|
645
|
44
|
100
|
|
|
|
145
|
if ($private) { |
|
646
|
7
|
|
|
|
|
24
|
$private = qq| |
|
647
|
|
|
|
|
|
|
my \$private_caller = caller(); |
|
648
|
|
|
|
|
|
|
if (\$private_caller ne __PACKAGE__) { |
|
649
|
|
|
|
|
|
|
die \"cannot call private method $name from \$private_caller\"; |
|
650
|
|
|
|
|
|
|
}|; |
|
651
|
7
|
|
|
|
|
22
|
$self->debug_step(sprintf(debug_step_24, $name), $private); |
|
652
|
7
|
|
|
|
|
27
|
return $private; |
|
653
|
|
|
|
|
|
|
} |
|
654
|
37
|
|
|
|
|
93
|
return q||; |
|
655
|
|
|
|
|
|
|
} |
|
656
|
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
sub build_type { |
|
658
|
134
|
|
|
134
|
0
|
504
|
my ($self, $name, $type, $value, $error_string, $subcode, $code) = @_; |
|
659
|
134
|
|
100
|
|
|
382
|
$value ||= '$value'; |
|
660
|
134
|
|
50
|
|
|
503
|
$code ||= ''; |
|
661
|
134
|
|
100
|
|
|
382
|
$subcode ||= ''; |
|
662
|
134
|
100
|
|
|
|
315
|
if ($type) { |
|
663
|
129
|
|
66
|
|
|
416
|
$error_string ||= qq|die qq{$type: invalid value $value for accessor $name};|; |
|
664
|
|
|
|
|
|
|
my $switch = switch |
|
665
|
|
|
|
|
|
|
qr/^(Any)$/ => sub { |
|
666
|
0
|
|
|
0
|
|
0
|
return ''; |
|
667
|
|
|
|
|
|
|
}, |
|
668
|
|
|
|
|
|
|
qr/^(Item)$/ => sub { |
|
669
|
0
|
|
|
0
|
|
0
|
return ''; |
|
670
|
|
|
|
|
|
|
}, |
|
671
|
|
|
|
|
|
|
qr/^(Bool)$/ => sub { |
|
672
|
1
|
|
|
1
|
|
38
|
return qq| |
|
673
|
|
|
|
|
|
|
my \$ref = ref $value; |
|
674
|
|
|
|
|
|
|
if ($subcode (\$ref \|\| 'SCALAR') ne 'SCALAR' \|\| (\$ref ? \$$value : $value) !~ m/^(1\|0)\$/) { |
|
675
|
|
|
|
|
|
|
$error_string |
|
676
|
|
|
|
|
|
|
} |
|
677
|
|
|
|
|
|
|
$value = !!(\$ref ? \$$value : $value) ? 1 : 0;|; |
|
678
|
|
|
|
|
|
|
}, |
|
679
|
|
|
|
|
|
|
qr/^(Str)$/ => sub { |
|
680
|
37
|
|
|
24
|
|
1585
|
return qq| |
|
681
|
|
|
|
|
|
|
if ($subcode ref $value) { |
|
682
|
|
|
|
|
|
|
$error_string |
|
683
|
|
|
|
|
|
|
}|; |
|
684
|
|
|
|
|
|
|
}, |
|
685
|
|
|
|
|
|
|
qr/^(Num)$/ => sub { |
|
686
|
0
|
|
|
0
|
|
0
|
return qq| |
|
687
|
|
|
|
|
|
|
if ($subcode ref $value \|\| $value !~ m/^[-+\\d]\\d*\\.?\\d\*\$/) { |
|
688
|
|
|
|
|
|
|
$error_string |
|
689
|
|
|
|
|
|
|
}|; |
|
690
|
|
|
|
|
|
|
}, |
|
691
|
|
|
|
|
|
|
qr/^(Int)$/ => sub { |
|
692
|
27
|
|
|
24
|
|
1457
|
return qq| |
|
693
|
|
|
|
|
|
|
if ($subcode ref $value \|\| $value !~ m/^[-+\\d]\\d\*\$/) { |
|
694
|
|
|
|
|
|
|
$error_string |
|
695
|
|
|
|
|
|
|
}|; |
|
696
|
|
|
|
|
|
|
}, |
|
697
|
|
|
|
|
|
|
qr/^(Ref)$/ => sub { |
|
698
|
0
|
|
|
0
|
|
0
|
return qq| |
|
699
|
|
|
|
|
|
|
if (! ref $value) { |
|
700
|
|
|
|
|
|
|
$error_string |
|
701
|
|
|
|
|
|
|
}|; |
|
702
|
|
|
|
|
|
|
}, |
|
703
|
|
|
|
|
|
|
qr/^(Ref\[(.*)\])$/ => sub { |
|
704
|
0
|
|
|
0
|
|
0
|
my ($val, @matches) = @_; |
|
705
|
0
|
0
|
|
|
|
0
|
$matches[1] = '"' . $matches[1] . '"' if $matches[1] =~ m/^[a-zA-Z]/; |
|
706
|
0
|
|
|
|
|
0
|
return qq| |
|
707
|
|
|
|
|
|
|
if ((ref($value) \|\| "") ne $matches[1]) { |
|
708
|
|
|
|
|
|
|
$error_string |
|
709
|
|
|
|
|
|
|
}|; |
|
710
|
|
|
|
|
|
|
}, |
|
711
|
|
|
|
|
|
|
qr/^(ScalarRef)$/ => sub { |
|
712
|
0
|
|
|
0
|
|
0
|
return qq| |
|
713
|
|
|
|
|
|
|
if ((ref($value) \|\| "") ne "SCALAR") { |
|
714
|
|
|
|
|
|
|
$error_string |
|
715
|
|
|
|
|
|
|
}|; |
|
716
|
|
|
|
|
|
|
}, |
|
717
|
|
|
|
|
|
|
qr/^(ScalarRef\[(.*)\])$/ => sub { |
|
718
|
1
|
|
|
0
|
|
72
|
my ($val, @matches) = @_; |
|
719
|
1
|
50
|
|
|
|
27
|
$matches[1] = '"' . $matches[1] . '"' if $matches[1] =~ m/^[a-zA-Z]/; |
|
720
|
1
|
|
|
|
|
8
|
return qq| |
|
721
|
|
|
|
|
|
|
if ((ref($value) \|\| "") ne $matches[1]) { |
|
722
|
|
|
|
|
|
|
$error_string |
|
723
|
|
|
|
|
|
|
}|; |
|
724
|
|
|
|
|
|
|
}, |
|
725
|
|
|
|
|
|
|
qr/^(ArrayRef)$/ => sub { |
|
726
|
1
|
|
|
1
|
|
86
|
return qq| |
|
727
|
|
|
|
|
|
|
if ($subcode (ref($value) \|\| "") ne "ARRAY") { |
|
728
|
|
|
|
|
|
|
$error_string |
|
729
|
|
|
|
|
|
|
}|; |
|
730
|
|
|
|
|
|
|
}, |
|
731
|
|
|
|
|
|
|
qr/^(ArrayRef\[(.*)\])$/ => sub { |
|
732
|
21
|
|
|
4
|
|
1808
|
my ($val, @matches) = @_; |
|
733
|
21
|
|
66
|
|
|
210
|
my $max = $matches[1] =~ s/\,\s*(\d+)\s*$// && $1; |
|
734
|
21
|
|
66
|
|
|
156
|
my $min = $matches[1] =~ s/\,\s*(\d+)\s*$// && $1; |
|
735
|
21
|
|
|
|
|
45
|
my $type = $matches[1]; |
|
736
|
21
|
|
|
|
|
60
|
@matches = ($type, $min, $max); |
|
737
|
21
|
|
|
|
|
91
|
my $code = qq| |
|
738
|
|
|
|
|
|
|
if ((ref($value) \|\| "") ne "ARRAY") { |
|
739
|
|
|
|
|
|
|
$error_string |
|
740
|
|
|
|
|
|
|
}|; |
|
741
|
21
|
|
|
|
|
118
|
my $new_error_string = $self->extend_error_string($error_string, $value, '$item', qq| expected $matches[0]|, $matches[0]); |
|
742
|
21
|
50
|
|
|
|
132
|
my $sub_code = $self->build_type($name, $matches[0], '$item', $new_error_string, ($matches[0] !~ m/^(Optional|Any|Item)/ ? qq|! defined(\$item) \|\|| : q||)); |
|
743
|
21
|
50
|
|
|
|
193
|
$code .= qq| |
|
744
|
|
|
|
|
|
|
for my \$item (\@{ $value }) {$sub_code |
|
745
|
|
|
|
|
|
|
}| if $sub_code; |
|
746
|
21
|
100
|
66
|
|
|
105
|
$code .= qq| |
|
747
|
|
|
|
|
|
|
my \$length = scalar \@{$value};| |
|
748
|
|
|
|
|
|
|
if $matches[1] || $matches[2]; |
|
749
|
21
|
100
|
|
|
|
117
|
$code .= qq| |
|
750
|
|
|
|
|
|
|
if (\$length < $matches[1]) { |
|
751
|
|
|
|
|
|
|
die qq{$val for $name must contain atleast $matches[1] items} |
|
752
|
|
|
|
|
|
|
}| |
|
753
|
|
|
|
|
|
|
if $matches[1] !~ m/^$/; |
|
754
|
21
|
100
|
|
|
|
97
|
$code .= qq| |
|
755
|
|
|
|
|
|
|
if (\$length > $matches[2]) { |
|
756
|
|
|
|
|
|
|
die qq{$val for $name must not be greater than $matches[2] items} |
|
757
|
|
|
|
|
|
|
}| |
|
758
|
|
|
|
|
|
|
if $matches[2] !~ m/^$/; |
|
759
|
21
|
|
|
|
|
139
|
return $code; |
|
760
|
|
|
|
|
|
|
}, |
|
761
|
|
|
|
|
|
|
qr/^(HashRef)$/ => sub { |
|
762
|
8
|
|
|
8
|
|
751
|
return qq| |
|
763
|
|
|
|
|
|
|
if ((ref($value) \|\| "") ne "HASH") { |
|
764
|
|
|
|
|
|
|
$error_string |
|
765
|
|
|
|
|
|
|
}|; |
|
766
|
|
|
|
|
|
|
}, |
|
767
|
|
|
|
|
|
|
qr/^(HashRef\[(.*)\])$/ => sub { |
|
768
|
6
|
|
|
2
|
|
586
|
my ($val, @matches) = @_; |
|
769
|
6
|
|
|
|
|
31
|
my $code = qq| |
|
770
|
|
|
|
|
|
|
if ((ref($value) \|\| "") ne "HASH") { |
|
771
|
|
|
|
|
|
|
$error_string |
|
772
|
|
|
|
|
|
|
}|; |
|
773
|
|
|
|
|
|
|
|
|
774
|
6
|
|
|
|
|
30
|
my $new_error_string = $self->extend_error_string($error_string, $value, '$item', qq| expected $matches[1]|, $matches[1]); |
|
775
|
6
|
50
|
|
|
|
40
|
my $sub_code = $self->build_type($name, $matches[1], '$item', $new_error_string, ($matches[1] !~ m/^(Optional|Any|Item)/ ? qq|! defined(\$item) \|\|| : q||)); |
|
776
|
6
|
50
|
|
|
|
55
|
$code .= qq| |
|
777
|
|
|
|
|
|
|
for my \$item (values \%{ $value }) {$sub_code |
|
778
|
|
|
|
|
|
|
}| if $sub_code; |
|
779
|
6
|
|
|
|
|
32
|
return $code; |
|
780
|
|
|
|
|
|
|
}, |
|
781
|
|
|
|
|
|
|
qr/^(CodeRef)$/ => sub { |
|
782
|
1
|
|
|
0
|
|
99
|
return qq| |
|
783
|
|
|
|
|
|
|
if ((ref($value) \|\| "") ne "CODE") { |
|
784
|
|
|
|
|
|
|
$error_string |
|
785
|
|
|
|
|
|
|
}|; |
|
786
|
|
|
|
|
|
|
}, |
|
787
|
|
|
|
|
|
|
qr/^(RegexpRef)$/ => sub { |
|
788
|
1
|
|
|
0
|
|
107
|
return qq| |
|
789
|
|
|
|
|
|
|
if ((ref($value) \|\| "") ne "Regexp") { |
|
790
|
|
|
|
|
|
|
$error_string |
|
791
|
|
|
|
|
|
|
}|; |
|
792
|
|
|
|
|
|
|
}, |
|
793
|
|
|
|
|
|
|
qr/^(GlobRef)$/ => sub { |
|
794
|
1
|
|
|
0
|
|
114
|
return qq| |
|
795
|
|
|
|
|
|
|
if ((ref($value) \|\| "") ne "GLOB") { |
|
796
|
|
|
|
|
|
|
$error_string |
|
797
|
|
|
|
|
|
|
}|; |
|
798
|
|
|
|
|
|
|
}, |
|
799
|
|
|
|
|
|
|
qr/^(Object)$/ => sub { |
|
800
|
4
|
|
|
3
|
|
502
|
return qq| |
|
801
|
|
|
|
|
|
|
if ((ref($value) \|\| "") =~ m/^(\|HASH\|ARRAY\|SCALAR\|CODE\|GLOB)\$/) { |
|
802
|
|
|
|
|
|
|
$error_string |
|
803
|
|
|
|
|
|
|
}|; |
|
804
|
|
|
|
|
|
|
}, |
|
805
|
|
|
|
|
|
|
qr/^(Map\[(.*)\])$/ => sub { |
|
806
|
7
|
|
|
2
|
|
880
|
my ($val, @matches) = @_; |
|
807
|
7
|
|
|
|
|
34
|
@matches = map { my $h = $_; $h =~ s/^\s*|\s*//g; $h; } split ',', $matches[1], 2; |
|
|
14
|
|
|
|
|
27
|
|
|
|
14
|
|
|
|
|
194
|
|
|
|
14
|
|
|
|
|
49
|
|
|
808
|
7
|
|
|
|
|
33
|
my $code = qq| |
|
809
|
|
|
|
|
|
|
if ((ref($value) \|\| "") ne "HASH") { |
|
810
|
|
|
|
|
|
|
$error_string |
|
811
|
|
|
|
|
|
|
}|; |
|
812
|
7
|
|
|
|
|
39
|
my $key_error_string = $self->extend_error_string($error_string, $value, '$key', qq| expected $matches[0]|); |
|
813
|
7
|
|
|
|
|
28
|
my $key_sub_code = $self->build_type($name, $matches[0], '$key', $key_error_string); |
|
814
|
7
|
|
|
|
|
23
|
$key_sub_code =~ s/ref \$key \|\| //;; |
|
815
|
7
|
|
|
|
|
31
|
my $value_error_string = $self->extend_error_string($error_string, $value, '$val', qq| expected $matches[1]|, $matches[0]); |
|
816
|
7
|
50
|
|
|
|
44
|
my $value_sub_code = $self->build_type($name, $matches[1], '$val', $value_error_string, ($matches[1] !~ m/^(Optional|Any|Item)/ ? qq|! defined(\$val) \|\|| : q||)); |
|
817
|
7
|
50
|
33
|
|
|
105
|
$code .= qq| |
|
818
|
|
|
|
|
|
|
for my \$key (keys \%{ $value }) { |
|
819
|
|
|
|
|
|
|
my \$val = ${value}->{\$key};$key_sub_code$value_sub_code |
|
820
|
|
|
|
|
|
|
}| if $key_sub_code || $value_sub_code; |
|
821
|
7
|
|
|
|
|
40
|
return $code; |
|
822
|
|
|
|
|
|
|
}, |
|
823
|
|
|
|
|
|
|
qr/^(Tuple\[(.*)\])$/ => sub { |
|
824
|
4
|
|
|
2
|
|
501
|
my ($val, @matches) = @_; |
|
825
|
4
|
|
|
|
|
23
|
@matches = map { my $h = $_; $h =~ s/^\s*|\s*//g; $h; } split ',', $matches[1]; |
|
|
16
|
|
|
|
|
25
|
|
|
|
16
|
|
|
|
|
101
|
|
|
|
16
|
|
|
|
|
40
|
|
|
826
|
4
|
|
|
|
|
22
|
my $code = qq| |
|
827
|
|
|
|
|
|
|
if ((ref($value) \|\| "") ne "ARRAY") { |
|
828
|
|
|
|
|
|
|
$error_string |
|
829
|
|
|
|
|
|
|
}|; |
|
830
|
4
|
|
|
|
|
10
|
my $i = 0; |
|
831
|
4
|
|
|
|
|
19
|
while (@matches) { |
|
832
|
10
|
|
|
|
|
24
|
my ($match) = (shift @matches); |
|
833
|
10
|
100
|
|
|
|
66
|
if ($match =~ m/(Map|Tuple|HashRef|ArrayRef|Dict)\[/) { |
|
834
|
|
|
|
|
|
|
my $lame = sub { |
|
835
|
6
|
|
|
|
|
13
|
my $copy = shift; |
|
836
|
6
|
|
|
|
|
40
|
while ($copy =~ s/\[[^\[\]]+\]//g) {} |
|
837
|
6
|
100
|
|
|
|
58
|
return ($copy =~ m/\[|\[/) ? 1 : 0; |
|
838
|
4
|
|
|
|
|
17
|
}; |
|
839
|
4
|
|
|
|
|
44
|
while ($lame->($match .= ', ' . shift @matches)) {} |
|
840
|
|
|
|
|
|
|
} |
|
841
|
10
|
|
|
|
|
33
|
(my $new_value = $value) .= qq|->[$i]|; |
|
842
|
10
|
|
|
|
|
43
|
my $item_error_string = $self->extend_error_string($error_string, $value, $new_value, qq| expected $match for index $i|, $match); |
|
843
|
10
|
50
|
|
|
|
56
|
my $key_sub_code = $self->build_type($name, $match, $new_value, $item_error_string, ($match !~ m/^(Optional|Any|Item)/ ? qq|! defined($new_value) \|\|| : q||)); |
|
844
|
10
|
|
|
|
|
58
|
$code .= $key_sub_code; |
|
845
|
10
|
|
|
|
|
39
|
$i++; |
|
846
|
|
|
|
|
|
|
} |
|
847
|
4
|
|
|
|
|
19
|
return $code; |
|
848
|
|
|
|
|
|
|
}, |
|
849
|
|
|
|
|
|
|
qr/^(Dict\[(.*)\])$/ => sub { |
|
850
|
5
|
|
|
4
|
|
667
|
my ($val, @matches) = @_; |
|
851
|
5
|
|
|
|
|
55
|
@matches = split ',', $matches[1]; |
|
852
|
5
|
|
|
|
|
91
|
my $sub_code; |
|
853
|
5
|
|
|
|
|
19
|
while (@matches) { |
|
854
|
14
|
|
|
|
|
40
|
my ($match) = (shift @matches); |
|
855
|
14
|
100
|
66
|
|
|
113
|
if (@matches && $match =~ m/(Map|Tuple|HashRef|ArrayRef|Dict)\[/) { |
|
856
|
|
|
|
|
|
|
my $lame = sub { |
|
857
|
23
|
|
|
|
|
47
|
my $copy = shift; |
|
858
|
23
|
|
|
|
|
273
|
while ($copy =~ s/\[[^\[\]]+\]//g) {} |
|
859
|
23
|
100
|
|
|
|
144
|
return ($copy =~ m/\[|\[/) ? 1 : 0; |
|
860
|
6
|
|
|
|
|
31
|
}; |
|
861
|
6
|
|
|
|
|
33
|
while ($lame->($match .= ', ' . shift @matches)) {} |
|
862
|
|
|
|
|
|
|
} |
|
863
|
14
|
|
|
|
|
54
|
my ($k, $v) = map { my $h = $_; $h =~ s/^\s*|\s*$//g; $h; } split('=>', $match, 2); |
|
|
28
|
|
|
|
|
46
|
|
|
|
28
|
|
|
|
|
183
|
|
|
|
28
|
|
|
|
|
89
|
|
|
864
|
14
|
|
|
|
|
41
|
(my $new_value = $value) .= qq|->{$k}|; |
|
865
|
14
|
|
|
|
|
55
|
my $new_error_string = $self->extend_error_string($error_string, $value, $new_value, qq| expected $v for $k|, $v); |
|
866
|
14
|
100
|
|
|
|
78
|
$sub_code .= $self->build_type($k, $v, $new_value, $new_error_string, ($v !~ m/^(Optional|Any|Item)/ ? qq|! defined($new_value) \|\|| : q||)); |
|
867
|
|
|
|
|
|
|
} |
|
868
|
5
|
|
|
|
|
52
|
my $code = qq| |
|
869
|
|
|
|
|
|
|
if ((ref($value) \|\| "") ne "HASH") { |
|
870
|
|
|
|
|
|
|
$error_string |
|
871
|
|
|
|
|
|
|
} $sub_code|; |
|
872
|
5
|
|
|
|
|
30
|
return $code; |
|
873
|
|
|
|
|
|
|
}, |
|
874
|
|
|
|
|
|
|
qr/^(Optional\[(.*)\])$/ => sub { |
|
875
|
4
|
|
|
4
|
|
550
|
my ($val, @matches) = @_; |
|
876
|
4
|
|
|
|
|
48
|
my $sub_code = $self->build_type($name, $matches[1], $value, $error_string); |
|
877
|
4
|
|
|
|
|
19
|
my $code = qq| |
|
878
|
|
|
|
|
|
|
if (defined $value) { $sub_code |
|
879
|
|
|
|
|
|
|
}|; |
|
880
|
4
|
|
|
|
|
19
|
return $code; |
|
881
|
129
|
|
|
|
|
8615
|
}; |
|
882
|
129
|
|
|
|
|
20739
|
$code .= $switch->($type); |
|
883
|
129
|
|
|
|
|
1116
|
$self->debug_step(sprintf(debug_step_26, $name), $code); |
|
884
|
|
|
|
|
|
|
} |
|
885
|
134
|
|
|
|
|
681
|
return $code; |
|
886
|
|
|
|
|
|
|
} |
|
887
|
|
|
|
|
|
|
|
|
888
|
|
|
|
|
|
|
sub extend_error_string { |
|
889
|
65
|
|
|
65
|
0
|
256
|
my ($self, $new_error_string, $value, $new_value, $message, $type) = @_; |
|
890
|
65
|
|
|
|
|
224
|
my $old_type = quotemeta(qq|$value = defined $value ? $value : 'undef';|); |
|
891
|
65
|
|
|
|
|
738
|
$new_error_string =~ s/^$old_type//; |
|
892
|
65
|
|
|
|
|
551
|
$new_error_string =~ s/\Q$value\E/$new_value/; |
|
893
|
65
|
|
|
|
|
333
|
$new_error_string =~ s/};$/$message};/; |
|
894
|
65
|
100
|
100
|
|
|
431
|
if ($type && $type !~ m/^(Optional|Any|Item)/) { |
|
895
|
54
|
|
|
|
|
206
|
$new_error_string = qq|$new_value = defined $new_value ? $new_value : 'undef';| . $new_error_string; |
|
896
|
|
|
|
|
|
|
} |
|
897
|
65
|
|
|
|
|
201
|
return $new_error_string; |
|
898
|
|
|
|
|
|
|
} |
|
899
|
|
|
|
|
|
|
|
|
900
|
|
|
|
|
|
|
sub build_macro_attributes { |
|
901
|
2
|
|
|
2
|
0
|
6
|
my ($self, $name, $token, $meta) = @_; |
|
902
|
|
|
|
|
|
|
return ( |
|
903
|
|
|
|
|
|
|
'default' => sub { |
|
904
|
0
|
|
|
0
|
|
0
|
my $value = shift; |
|
905
|
0
|
|
|
|
|
0
|
push @{$meta->{$name}->{caught}}, $value; |
|
|
0
|
|
|
|
|
0
|
|
|
906
|
|
|
|
|
|
|
}, |
|
907
|
|
|
|
|
|
|
qr/^(\:a|\:alias)/ => sub { |
|
908
|
2
|
|
|
2
|
|
53
|
my $value = shift; |
|
909
|
2
|
|
|
|
|
14
|
$value =~ s/^\:(a|alias)\(\s*(.*)\s*\)$/$2/sg; |
|
910
|
2
|
|
|
|
|
12
|
push @{$meta->{$name}->{alias}}, split(' ', $value); |
|
|
2
|
|
|
|
|
17
|
|
|
911
|
|
|
|
|
|
|
}, |
|
912
|
|
|
|
|
|
|
qr/^(\{)/ => sub { |
|
913
|
2
|
|
|
2
|
|
46
|
my $value = shift; |
|
914
|
2
|
|
|
|
|
19
|
$value =~ s/^\{|\}$//g; |
|
915
|
2
|
|
|
|
|
248
|
$meta->{$name}->{code} = eval qq|sub { my (\$self, \$mg, \@params) = \@_; $value }|; |
|
916
|
|
|
|
|
|
|
}, |
|
917
|
2
|
|
|
|
|
33
|
); |
|
918
|
|
|
|
|
|
|
} |
|
919
|
|
|
|
|
|
|
|
|
920
|
|
|
|
|
|
|
sub build_macro { |
|
921
|
2
|
|
|
2
|
0
|
7
|
my ($self, $mg, $class) = @_; |
|
922
|
2
|
|
|
|
|
5
|
my $meta = $self->{macros}; |
|
923
|
2
|
|
|
|
|
4
|
for my $macro (@{$class}) { |
|
|
2
|
|
|
|
|
6
|
|
|
924
|
4
|
|
|
|
|
14
|
$self->debug_step(debug_step_6, $macro); |
|
925
|
4
|
100
|
|
|
|
23
|
if ($macro->[-1] !~ m/^{/) { |
|
926
|
2
|
|
|
|
|
5
|
my $include = sprintf "Hades::Macro::%s", shift @{$macro}; |
|
|
2
|
|
|
|
|
19
|
|
|
927
|
2
|
|
|
|
|
11
|
$self->debug_step(sprintf(debug_step_7, $include), $macro); |
|
928
|
2
|
|
|
|
|
196
|
eval qq|require $include|; |
|
929
|
2
|
50
|
|
|
|
18
|
die $@ if $@; |
|
930
|
2
|
100
|
|
|
|
23
|
my $include_meta = $include->new($macro->[0] ? do { |
|
931
|
1
|
|
|
|
|
19
|
$macro->[0] =~ s/^\[|\]$//g; |
|
932
|
1
|
|
|
|
|
81
|
( eval qq|$macro->[0]| ); |
|
933
|
|
|
|
|
|
|
} : ())->meta; |
|
934
|
2
|
|
|
|
|
28
|
$self->debug_step(sprintf(debug_step_8, $include), $include_meta); |
|
935
|
2
|
|
|
|
|
5
|
$meta = {%{$meta}, %{$include_meta}}; |
|
|
2
|
|
|
|
|
6
|
|
|
|
2
|
|
|
|
|
21
|
|
|
936
|
|
|
|
|
|
|
} else { |
|
937
|
2
|
|
|
|
|
5
|
my $name = shift @{$macro}; |
|
|
2
|
|
|
|
|
5
|
|
|
938
|
2
|
|
|
|
|
8
|
$self->debug_step(sprintf(debug_step_9, $name), $macro); |
|
939
|
2
|
|
|
|
|
8
|
$meta->{$name}->{meta} = 'MACRO'; |
|
940
|
2
|
|
|
|
|
8
|
my $switch = switch( |
|
941
|
|
|
|
|
|
|
$self->build_macro_attributes($name, $macro, $meta) |
|
942
|
|
|
|
|
|
|
); |
|
943
|
2
|
|
|
|
|
79
|
$switch->(shift @{$macro}) while scalar @{$macro}; |
|
|
6
|
|
|
|
|
36
|
|
|
|
4
|
|
|
|
|
26
|
|
|
944
|
2
|
|
|
|
|
9
|
$self->debug_step(sprintf(debug_step_10, $name), $meta->{$name}); |
|
945
|
2
|
50
|
|
|
|
6
|
if ($meta->{$name}->{alias}) { |
|
946
|
2
|
|
|
|
|
4
|
for (@{$meta->{$name}->{alias}}) { |
|
|
2
|
|
|
|
|
7
|
|
|
947
|
2
|
|
|
|
|
31
|
$meta->{$_} = $meta->{$name}; |
|
948
|
|
|
|
|
|
|
} |
|
949
|
|
|
|
|
|
|
} |
|
950
|
|
|
|
|
|
|
} |
|
951
|
|
|
|
|
|
|
} |
|
952
|
2
|
|
|
|
|
10
|
$self->debug_step(debug_step_11, $meta); |
|
953
|
2
|
|
|
|
|
7
|
$self->{macros} = $meta; |
|
954
|
|
|
|
|
|
|
} |
|
955
|
|
|
|
|
|
|
|
|
956
|
|
|
|
|
|
|
sub index { |
|
957
|
7344
|
|
|
7344
|
0
|
10517
|
my ($self, $index) = @_; |
|
958
|
7344
|
|
|
|
|
14874
|
return substr $self->{eval}, $index, 1; |
|
959
|
|
|
|
|
|
|
} |
|
960
|
|
|
|
|
|
|
|
|
961
|
|
|
|
|
|
|
sub build_test_data { |
|
962
|
276
|
|
|
276
|
0
|
670
|
my ($self, $type, $name, $required) = @_; |
|
963
|
|
|
|
|
|
|
my $switch = switch |
|
964
|
|
|
|
|
|
|
qr/^(Any)$/ => sub { |
|
965
|
15
|
|
|
15
|
|
364
|
return $self->_generate_test_string; |
|
966
|
|
|
|
|
|
|
}, |
|
967
|
|
|
|
|
|
|
qr/^(Item)$/ => sub { |
|
968
|
0
|
|
|
0
|
|
0
|
return $self->_generate_test_string; |
|
969
|
|
|
|
|
|
|
}, |
|
970
|
|
|
|
|
|
|
qr/^(Bool)$/ => sub { |
|
971
|
2
|
|
|
2
|
|
69
|
return (q|1|, q|[]|, q|{}|); |
|
972
|
|
|
|
|
|
|
}, |
|
973
|
|
|
|
|
|
|
qr/^(Str)$/ => sub { |
|
974
|
73
|
|
|
47
|
|
2824
|
return ($self->_generate_test_string, q|[]|, q|\1|); |
|
975
|
|
|
|
|
|
|
}, |
|
976
|
|
|
|
|
|
|
qr/^(Num)$/ => sub { |
|
977
|
0
|
|
|
0
|
|
0
|
return (q|100.555|, q|[]|, $self->_generate_test_string); |
|
978
|
|
|
|
|
|
|
}, |
|
979
|
|
|
|
|
|
|
qr/^(Int)$/ => sub { |
|
980
|
62
|
|
|
56
|
|
3144
|
return (q|10|, q|[]|, $self->_generate_test_string); |
|
981
|
|
|
|
|
|
|
}, |
|
982
|
|
|
|
|
|
|
qr/^(Ref)$/ => sub { |
|
983
|
0
|
|
|
0
|
|
0
|
return (q|{ test => 'test' }|, $self->_generate_test_string, q|1|); |
|
984
|
|
|
|
|
|
|
}, |
|
985
|
|
|
|
|
|
|
qr/^(Ref\[(.*)\])$/ => sub { |
|
986
|
0
|
|
|
0
|
|
0
|
my ($val, @matches) = @_; |
|
987
|
0
|
0
|
|
|
|
0
|
$matches[1] = '"' . $matches[1] . '"' if $matches[1] =~ m/^[a-zA-Z]/; |
|
988
|
|
|
|
|
|
|
return ( |
|
989
|
0
|
|
|
|
|
0
|
qq|bless({ test => 'test' }, $matches[1])|, |
|
990
|
|
|
|
|
|
|
qq|bless({ test => 'test' }, $matches[1] . 'Error')|, |
|
991
|
|
|
|
|
|
|
$self->_generate_test_string |
|
992
|
|
|
|
|
|
|
); |
|
993
|
|
|
|
|
|
|
}, |
|
994
|
|
|
|
|
|
|
qr/^(ScalarRef)$/ => sub { |
|
995
|
0
|
|
|
0
|
|
0
|
return ( q|\1|, 1, q|[]|); |
|
996
|
|
|
|
|
|
|
}, |
|
997
|
|
|
|
|
|
|
qr/^(ScalarRef\[(.*)\])$/ => sub { |
|
998
|
2
|
|
|
0
|
|
141
|
my ($val, @matches) = @_; |
|
999
|
2
|
50
|
|
|
|
12
|
$matches[1] = '"' . $matches[1] . '"' if $matches[1] =~ m/^[a-zA-Z]/; |
|
1000
|
|
|
|
|
|
|
return ( |
|
1001
|
2
|
|
|
|
|
11
|
qq|do { my \$okay = ''; bless( \\\$okay, $matches[1]) }|, |
|
1002
|
|
|
|
|
|
|
qq|do { my \$okay = ''; bless( \\\$okay, $matches[1] . 'Error') }|, |
|
1003
|
|
|
|
|
|
|
$self->_generate_test_string, |
|
1004
|
|
|
|
|
|
|
q|{}| |
|
1005
|
|
|
|
|
|
|
); |
|
1006
|
|
|
|
|
|
|
}, |
|
1007
|
|
|
|
|
|
|
qr/^(ArrayRef)$/ => sub { |
|
1008
|
|
|
|
|
|
|
return ( |
|
1009
|
2
|
|
|
2
|
|
163
|
qq|['test']|, |
|
1010
|
|
|
|
|
|
|
qq|{}|, |
|
1011
|
|
|
|
|
|
|
$self->_generate_test_string |
|
1012
|
|
|
|
|
|
|
); |
|
1013
|
|
|
|
|
|
|
}, |
|
1014
|
|
|
|
|
|
|
qr/^(ArrayRef\[(.*)\])$/ => sub { |
|
1015
|
42
|
|
|
8
|
|
3483
|
my ($val, @matches) = @_; |
|
1016
|
42
|
|
66
|
|
|
387
|
my $max = $matches[1] =~ s/\,\s*(\d+)\s*$// && $1; |
|
1017
|
42
|
|
66
|
|
|
253
|
my $min = $matches[1] =~ s/\,\s*(\d+)\s*$// && $1; |
|
1018
|
42
|
|
|
|
|
83
|
my $type = $matches[1]; |
|
1019
|
42
|
|
|
|
|
113
|
@matches = ($type, $min, $max); |
|
1020
|
42
|
|
|
|
|
132
|
my @values = $self->build_test_data($matches[0], $name, $required); |
|
1021
|
42
|
50
|
|
|
|
2158
|
push @values, 'undef' unless $matches[0] =~ m/^Optional/; |
|
1022
|
|
|
|
|
|
|
return ( |
|
1023
|
|
|
|
|
|
|
(map { |
|
1024
|
318
|
|
|
|
|
458
|
my $v = $_; |
|
1025
|
318
|
|
100
|
|
|
747
|
sprintf q|[ %s ]|, join ", ", map { $v } 0 .. ($matches[1] || 1) - 1; |
|
|
372
|
|
|
|
|
1314
|
|
|
1026
|
|
|
|
|
|
|
} @values), |
|
1027
|
|
|
|
|
|
|
(($matches[1] || 0) > 0 ? ( |
|
1028
|
|
|
|
|
|
|
qq|[]| |
|
1029
|
|
|
|
|
|
|
) : ( )), |
|
1030
|
|
|
|
|
|
|
($matches[2] ? ( |
|
1031
|
42
|
100
|
100
|
|
|
83
|
sprintf q|[ %s ]|, join ", ", map { $values[0] } 0 .. $matches[2] + 1 |
|
|
744
|
100
|
|
|
|
1289
|
|
|
1032
|
|
|
|
|
|
|
) : ( )), |
|
1033
|
|
|
|
|
|
|
q|{}|, |
|
1034
|
|
|
|
|
|
|
$self->_generate_test_string |
|
1035
|
|
|
|
|
|
|
); |
|
1036
|
|
|
|
|
|
|
}, |
|
1037
|
|
|
|
|
|
|
qr/^(HashRef)$/ => sub { |
|
1038
|
|
|
|
|
|
|
return ( |
|
1039
|
11
|
|
|
11
|
|
1041
|
q|{ 'test' => 'test' }|, |
|
1040
|
|
|
|
|
|
|
q|[]|, |
|
1041
|
|
|
|
|
|
|
$self->_generate_test_string |
|
1042
|
|
|
|
|
|
|
); |
|
1043
|
|
|
|
|
|
|
}, |
|
1044
|
|
|
|
|
|
|
qr/^(HashRef\[(.*)\])$/ => sub { |
|
1045
|
12
|
|
|
4
|
|
1184
|
my ($val, @matches) = @_; |
|
1046
|
12
|
|
|
|
|
42
|
my @values = $self->build_test_data($matches[1], $name, $required); |
|
1047
|
12
|
50
|
|
|
|
649
|
push @values, 'undef' unless $matches[1] =~ qr/^Optional/; |
|
1048
|
|
|
|
|
|
|
return ( |
|
1049
|
|
|
|
|
|
|
(map { |
|
1050
|
12
|
|
|
|
|
88
|
sprintf q|{ test => %s }|, $_; |
|
|
114
|
|
|
|
|
288
|
|
|
1051
|
|
|
|
|
|
|
} @values), |
|
1052
|
|
|
|
|
|
|
q|[]|, |
|
1053
|
|
|
|
|
|
|
$self->_generate_test_string |
|
1054
|
|
|
|
|
|
|
); |
|
1055
|
|
|
|
|
|
|
}, |
|
1056
|
|
|
|
|
|
|
qr/^(CodeRef)$/ => sub { |
|
1057
|
|
|
|
|
|
|
return ( |
|
1058
|
2
|
|
|
0
|
|
216
|
q|$sub|, |
|
1059
|
|
|
|
|
|
|
q|[]|, |
|
1060
|
|
|
|
|
|
|
$self->_generate_test_string |
|
1061
|
|
|
|
|
|
|
); |
|
1062
|
|
|
|
|
|
|
}, |
|
1063
|
|
|
|
|
|
|
qr/^(RegexpRef)$/ => sub { |
|
1064
|
|
|
|
|
|
|
return ( |
|
1065
|
2
|
|
|
0
|
|
220
|
q|qr/abc/|, |
|
1066
|
|
|
|
|
|
|
q|[]|, |
|
1067
|
|
|
|
|
|
|
$self->_generate_test_string |
|
1068
|
|
|
|
|
|
|
); |
|
1069
|
|
|
|
|
|
|
}, |
|
1070
|
|
|
|
|
|
|
qr/^(GlobRef)$/ => sub { |
|
1071
|
|
|
|
|
|
|
return ( |
|
1072
|
2
|
|
|
0
|
|
227
|
q|$globref|, |
|
1073
|
|
|
|
|
|
|
q|[]|, |
|
1074
|
|
|
|
|
|
|
$self->_generate_test_string |
|
1075
|
|
|
|
|
|
|
); |
|
1076
|
|
|
|
|
|
|
}, |
|
1077
|
|
|
|
|
|
|
qr/^(Object)$/ => sub { |
|
1078
|
|
|
|
|
|
|
return ( |
|
1079
|
5
|
|
|
3
|
|
563
|
q|bless({}, 'Test')|, |
|
1080
|
|
|
|
|
|
|
q|[]|, |
|
1081
|
|
|
|
|
|
|
$self->_generate_test_string |
|
1082
|
|
|
|
|
|
|
); |
|
1083
|
|
|
|
|
|
|
}, |
|
1084
|
|
|
|
|
|
|
qr/^(Map\[(.*)\])$/ => sub { |
|
1085
|
14
|
|
|
4
|
|
1727
|
my ($val, @matches) = @_; |
|
1086
|
14
|
|
|
|
|
62
|
@matches = map { my $h = $_; $h =~ s/^\s*|\s*//g; $h; } split ',', $matches[1], 2; |
|
|
28
|
|
|
|
|
47
|
|
|
|
28
|
|
|
|
|
223
|
|
|
|
28
|
|
|
|
|
143
|
|
|
1087
|
14
|
|
|
|
|
52
|
my @keys = $self->build_test_data($matches[0], $name, $required); |
|
1088
|
14
|
|
|
|
|
862
|
my @values = $self->build_test_data($matches[1], $name, $required); |
|
1089
|
14
|
50
|
|
|
|
628
|
push @values, 'undef' unless $matches[1] =~ m/^Optional/; |
|
1090
|
|
|
|
|
|
|
return ( |
|
1091
|
|
|
|
|
|
|
(map { |
|
1092
|
14
|
|
|
|
|
32
|
sprintf q|{ %s => %s }|, $keys[0], $_; |
|
|
104
|
|
|
|
|
272
|
|
|
1093
|
|
|
|
|
|
|
} @values), |
|
1094
|
|
|
|
|
|
|
q|[]|, |
|
1095
|
|
|
|
|
|
|
$self->_generate_test_string |
|
1096
|
|
|
|
|
|
|
); |
|
1097
|
|
|
|
|
|
|
}, |
|
1098
|
|
|
|
|
|
|
qr/^(Tuple\[(.*)\])$/ => sub { |
|
1099
|
8
|
|
|
4
|
|
1102
|
my ($val, @matches) = @_; |
|
1100
|
8
|
|
|
|
|
45
|
@matches = map { my $h = $_; $h =~ s/^\s*|\s*//g; $h; } split ',', $matches[1]; |
|
|
32
|
|
|
|
|
50
|
|
|
|
32
|
|
|
|
|
200
|
|
|
|
32
|
|
|
|
|
78
|
|
|
1101
|
8
|
|
|
|
|
20
|
my @tuple; |
|
1102
|
8
|
|
|
|
|
33
|
while (@matches) { |
|
1103
|
20
|
|
|
|
|
757
|
my ($match) = (shift @matches); |
|
1104
|
20
|
100
|
|
|
|
172
|
if ($match =~ m/(Map|Tuple|HashRef|ArrayRef|Dict)\[/) { |
|
1105
|
|
|
|
|
|
|
my $lame = sub { |
|
1106
|
12
|
|
|
|
|
22
|
my $copy = shift; |
|
1107
|
12
|
|
|
|
|
79
|
while ($copy =~ s/\[[^\[\]]+\]//g) {} |
|
1108
|
12
|
100
|
|
|
|
64
|
return ($copy =~ m/\[|\[/) ? 1 : 0; |
|
1109
|
8
|
|
|
|
|
32
|
}; |
|
1110
|
8
|
|
|
|
|
32
|
while ($lame->($match .= ', ' . shift @matches)) {} |
|
1111
|
|
|
|
|
|
|
} |
|
1112
|
20
|
50
|
|
|
|
60
|
push @tuple, [ |
|
1113
|
|
|
|
|
|
|
$self->build_test_data($match, $name, $required), ($_ =~ m/^Optional/ ? () : 'undef') |
|
1114
|
|
|
|
|
|
|
]; |
|
1115
|
|
|
|
|
|
|
} |
|
1116
|
8
|
|
|
|
|
372
|
my $d = 0; |
|
1117
|
|
|
|
|
|
|
return ( |
|
1118
|
|
|
|
|
|
|
(map { |
|
1119
|
8
|
|
|
|
|
18
|
my ($tup, $m) = ($_, 0, $d++); |
|
|
20
|
|
|
|
|
45
|
|
|
1120
|
|
|
|
|
|
|
map { |
|
1121
|
124
|
|
|
|
|
221
|
my $ah = $_; |
|
1122
|
|
|
|
|
|
|
$m++ == 0 && $d > 1 ? () : |
|
1123
|
124
|
100
|
100
|
|
|
332
|
sprintf q|[ %s ]|, join ', ', map {$d - 1 == $_ ? $ah : $tuple[$_]->[0] } 0 .. $#tuple; |
|
|
308
|
100
|
|
|
|
780
|
|
|
1124
|
20
|
|
|
|
|
32
|
} @{$tup}; |
|
|
20
|
|
|
|
|
34
|
|
|
1125
|
|
|
|
|
|
|
} @tuple), |
|
1126
|
|
|
|
|
|
|
q|[]|, |
|
1127
|
|
|
|
|
|
|
q|{}|, |
|
1128
|
|
|
|
|
|
|
$self->_generate_test_string |
|
1129
|
|
|
|
|
|
|
); |
|
1130
|
|
|
|
|
|
|
}, |
|
1131
|
|
|
|
|
|
|
qr/^(Dict\[(.*)\])$/ => sub { |
|
1132
|
14
|
|
|
12
|
|
1929
|
my ($val, @matches) = @_; |
|
1133
|
14
|
|
|
|
|
110
|
@matches = split ',', $matches[1]; |
|
1134
|
14
|
|
|
|
|
35
|
my %map; |
|
1135
|
14
|
|
|
|
|
41
|
while (@matches) { |
|
1136
|
34
|
|
|
|
|
77
|
my ($match) = (shift @matches); |
|
1137
|
34
|
100
|
100
|
|
|
219
|
if (@matches && $match =~ m/(Map|Tuple|ArrayRef|Dict)\[/) { |
|
1138
|
|
|
|
|
|
|
my $lame = sub { |
|
1139
|
46
|
|
|
|
|
74
|
my $copy = shift; |
|
1140
|
46
|
|
|
|
|
317
|
while ($copy =~ s/\[[^\[\]]+\]//g) {} |
|
1141
|
46
|
100
|
|
|
|
214
|
return ($copy =~ m/\[|\[/) ? 1 : 0; |
|
1142
|
12
|
|
|
|
|
128
|
}; |
|
1143
|
12
|
|
|
|
|
75
|
while ($lame->($match .= ', ' . shift @matches)) {} |
|
1144
|
|
|
|
|
|
|
} |
|
1145
|
34
|
|
|
|
|
128
|
my ($k, $v) = map { my $h = $_; $h =~ s/^\s*|\s*$//g; $h; } split('=>', $match, 2); |
|
|
68
|
|
|
|
|
108
|
|
|
|
68
|
|
|
|
|
429
|
|
|
|
68
|
|
|
|
|
177
|
|
|
1146
|
34
|
|
|
|
|
108
|
$v =~ s/,\s*$//; |
|
1147
|
34
|
|
|
|
|
91
|
my @values = $self->build_test_data($v, $name, $required); |
|
1148
|
34
|
100
|
|
|
|
1744
|
push @values, 'undef' unless $v =~ m/^Optional/; |
|
1149
|
34
|
|
|
|
|
93
|
$map{$k} = \@values; |
|
1150
|
34
|
|
|
|
|
55
|
push @{ $map{_dict_columns} }, $k; |
|
|
34
|
|
|
|
|
145
|
|
|
1151
|
|
|
|
|
|
|
} |
|
1152
|
14
|
|
|
|
|
27
|
my $d = 0; |
|
1153
|
|
|
|
|
|
|
return ( |
|
1154
|
|
|
|
|
|
|
(map { |
|
1155
|
34
|
|
|
|
|
77
|
my ($dict, $m) = ($_, 0, $d++); |
|
1156
|
|
|
|
|
|
|
map { |
|
1157
|
290
|
|
|
|
|
456
|
my $ah = $_; |
|
1158
|
|
|
|
|
|
|
$m++ == 0 && $d > 1 ? () : |
|
1159
|
290
|
100
|
100
|
|
|
639
|
sprintf q|{ %s }|, join ', ', map {$dict eq $_ ? qq|$_ => $ah| : sprintf( q|%s => %s|, $_, $map{$_}->[0]) } @{$map{_dict_columns}}; |
|
|
680
|
100
|
|
|
|
2215
|
|
|
|
270
|
|
|
|
|
389
|
|
|
1160
|
34
|
|
|
|
|
42
|
} @{$map{$dict}}; |
|
|
34
|
|
|
|
|
61
|
|
|
1161
|
14
|
|
|
|
|
23
|
} @{$map{_dict_columns}}), q|{}|, q|[]|, $self->_generate_test_string |
|
|
14
|
|
|
|
|
33
|
|
|
1162
|
|
|
|
|
|
|
); |
|
1163
|
|
|
|
|
|
|
}, |
|
1164
|
|
|
|
|
|
|
qr/^(Optional\[(.*)\])$/ => sub { |
|
1165
|
8
|
|
|
8
|
|
1107
|
my ($val, @matches) = @_; |
|
1166
|
8
|
|
|
|
|
46
|
my @values = $self->build_test_data($matches[1], $name, $required); |
|
1167
|
8
|
100
|
|
|
|
378
|
$values[0] = 'undef' unless $required; |
|
1168
|
8
|
|
|
|
|
30
|
return @values; |
|
1169
|
276
|
|
|
|
|
12259
|
}; |
|
1170
|
276
|
|
|
|
|
41373
|
return $switch->($type); |
|
1171
|
|
|
|
|
|
|
} |
|
1172
|
|
|
|
|
|
|
|
|
1173
|
|
|
|
|
|
|
sub build_tests { |
|
1174
|
105
|
|
|
105
|
0
|
12704
|
my ($self, $name, $meta, $mod, $class) = @_; |
|
1175
|
105
|
|
|
|
|
230
|
my @tests = (); |
|
1176
|
|
|
|
|
|
|
$mod ? $mod ne 'new' ? do { |
|
1177
|
21
|
|
100
|
|
|
96
|
my ($valid) = $self->build_test_data($meta->{type}->[0] || 'Any', $name); |
|
1178
|
21
|
|
|
|
|
1187
|
push @tests, ['deep', qq|\$obj->$name($valid)|, $valid]; |
|
1179
|
|
|
|
|
|
|
} : do { |
|
1180
|
15
|
|
|
|
|
31
|
my %test_data; |
|
1181
|
|
|
|
|
|
|
map { |
|
1182
|
46
|
50
|
|
|
|
1941
|
unless ($meta->{$_}->{no_success_test}) { |
|
1183
|
46
|
|
|
|
|
73
|
push @{$test_data{test_data_columns}}, $_; |
|
|
46
|
|
|
|
|
133
|
|
|
1184
|
46
|
100
|
|
|
|
210
|
$test_data{$_} = [ $self->build_test_data($meta->{$_}->{type}->[0] ? $meta->{$_}->{type}->[0] : 'Any', '', 1) ] |
|
1185
|
|
|
|
|
|
|
} |
|
1186
|
15
|
|
|
|
|
32
|
} grep { $meta->{$_}->{meta} eq 'ACCESSOR' } keys %{$meta}; |
|
|
69
|
|
|
|
|
187
|
|
|
|
15
|
|
|
|
|
77
|
|
|
1187
|
15
|
|
|
|
|
630
|
my $valid = join(', ', map { sprintf '%s => %s', $_, $test_data{$_}->[0] } grep { $meta->{$_}->{required} } @{$test_data{test_data_columns}}); |
|
|
12
|
|
|
|
|
56
|
|
|
|
46
|
|
|
|
|
155
|
|
|
|
15
|
|
|
|
|
51
|
|
|
1188
|
|
|
|
|
|
|
push @tests, [ |
|
1189
|
|
|
|
|
|
|
'ok', |
|
1190
|
|
|
|
|
|
|
sprintf( |
|
1191
|
|
|
|
|
|
|
'my $obj = %s->new({%s})', |
|
1192
|
|
|
|
|
|
|
$class->{CURRENT}->{NAME}, |
|
1193
|
|
|
|
|
|
|
$valid |
|
1194
|
|
|
|
|
|
|
) |
|
1195
|
|
|
|
|
|
|
], [ |
|
1196
|
|
|
|
|
|
|
'ok', |
|
1197
|
|
|
|
|
|
|
sprintf( |
|
1198
|
|
|
|
|
|
|
'$obj = %s->new(%s)', |
|
1199
|
|
|
|
|
|
|
$class->{CURRENT}->{NAME}, |
|
1200
|
15
|
|
|
|
|
150
|
$valid |
|
1201
|
|
|
|
|
|
|
) |
|
1202
|
|
|
|
|
|
|
], ['isa_ok', '$obj', qq|'$class->{CURRENT}->{NAME}'|]; |
|
1203
|
15
|
|
|
|
|
41
|
my $d = 0; |
|
1204
|
15
|
|
|
|
|
28
|
for my $key (@{$test_data{test_data_columns}}) { |
|
|
15
|
|
|
|
|
52
|
|
|
1205
|
46
|
100
|
|
|
|
159
|
if ($meta->{$key}->{default}) { |
|
|
|
100
|
|
|
|
|
|
|
1206
|
17
|
100
|
|
|
|
28
|
$valid = join(', ', map { $key ne $_ ? ( sprintf '%s => %s', $_, $test_data{$_}->[0] ) : () } @{$test_data{test_data_columns}}); |
|
|
84
|
|
|
|
|
235
|
|
|
|
17
|
|
|
|
|
36
|
|
|
1207
|
|
|
|
|
|
|
push @tests, [ |
|
1208
|
|
|
|
|
|
|
'ok', |
|
1209
|
|
|
|
|
|
|
sprintf( |
|
1210
|
|
|
|
|
|
|
'$obj = %s->new({%s})', |
|
1211
|
|
|
|
|
|
|
$class->{CURRENT}->{NAME}, |
|
1212
|
|
|
|
|
|
|
$valid |
|
1213
|
|
|
|
|
|
|
), |
|
1214
|
|
|
|
|
|
|
], [ |
|
1215
|
|
|
|
|
|
|
'ok', |
|
1216
|
|
|
|
|
|
|
sprintf( |
|
1217
|
|
|
|
|
|
|
'$obj = %s->new(%s)', |
|
1218
|
|
|
|
|
|
|
$class->{CURRENT}->{NAME}, |
|
1219
|
|
|
|
|
|
|
$valid |
|
1220
|
|
|
|
|
|
|
), |
|
1221
|
17
|
|
|
|
|
123
|
], [ 'deep', qq|\$obj->$key|, $meta->{$key}->{default} ]; |
|
1222
|
|
|
|
|
|
|
} elsif ($meta->{$key}->{required}) { |
|
1223
|
|
|
|
|
|
|
push @tests, [ |
|
1224
|
|
|
|
|
|
|
'eval', |
|
1225
|
|
|
|
|
|
|
sprintf( |
|
1226
|
|
|
|
|
|
|
'$obj = %s->new({%s})', |
|
1227
|
|
|
|
|
|
|
$class->{CURRENT}->{NAME}, |
|
1228
|
3
|
100
|
|
|
|
12
|
join(', ', map { $key ne $_ ? ( sprintf '%s => %s', $_, $test_data{$_}->[0] ) : () } @{$test_data{test_data_columns}}) |
|
|
24
|
|
|
|
|
85
|
|
|
|
3
|
|
|
|
|
55
|
|
|
1229
|
|
|
|
|
|
|
), |
|
1230
|
|
|
|
|
|
|
'required' |
|
1231
|
|
|
|
|
|
|
]; |
|
1232
|
|
|
|
|
|
|
} |
|
1233
|
46
|
|
|
|
|
75
|
my $m = 0; |
|
1234
|
46
|
|
|
|
|
68
|
for my $ah (@{$test_data{$key}}) { |
|
|
46
|
|
|
|
|
88
|
|
|
1235
|
349
|
100
|
|
|
|
643
|
if ($m++ == 0) { |
|
1236
|
46
|
100
|
|
|
|
117
|
next if $d > 0; |
|
1237
|
|
|
|
|
|
|
push @tests, [ |
|
1238
|
|
|
|
|
|
|
'ok', |
|
1239
|
|
|
|
|
|
|
sprintf q|$obj = %s->new({ %s })|, |
|
1240
|
|
|
|
|
|
|
$class->{CURRENT}->{NAME}, |
|
1241
|
11
|
100
|
|
|
|
37
|
join ', ', map {$key eq $_ ? qq|$_ => $ah| : sprintf( q|%s => %s|, $_, $test_data{$_}->[0]) } @{$test_data{test_data_columns}} |
|
|
46
|
|
|
|
|
190
|
|
|
|
11
|
|
|
|
|
25
|
|
|
1242
|
|
|
|
|
|
|
]; |
|
1243
|
|
|
|
|
|
|
} else { |
|
1244
|
|
|
|
|
|
|
push @tests, [ |
|
1245
|
|
|
|
|
|
|
'eval', |
|
1246
|
|
|
|
|
|
|
sprintf( |
|
1247
|
|
|
|
|
|
|
q|$obj = %s->new({ %s })|, |
|
1248
|
|
|
|
|
|
|
$class->{CURRENT}->{NAME}, |
|
1249
|
303
|
100
|
|
|
|
482
|
join ', ', map {$key eq $_ ? qq|$_ => $ah| : sprintf( q|%s => %s|, $_, $test_data{$_}->[0]) } @{$test_data{test_data_columns}} |
|
|
2892
|
|
|
|
|
8359
|
|
|
|
303
|
|
|
|
|
476
|
|
|
1250
|
|
|
|
|
|
|
), |
|
1251
|
|
|
|
|
|
|
'invalid|type|constraint|greater|atleast' |
|
1252
|
|
|
|
|
|
|
]; |
|
1253
|
|
|
|
|
|
|
} |
|
1254
|
|
|
|
|
|
|
} |
|
1255
|
46
|
|
|
|
|
145
|
$d++; |
|
1256
|
|
|
|
|
|
|
} |
|
1257
|
|
|
|
|
|
|
} : $meta->{meta} eq 'ACCESSOR' ? do { |
|
1258
|
46
|
|
|
|
|
199
|
push @tests, ['can_ok', qq|\$obj|, qq|'$name'|]; |
|
1259
|
|
|
|
|
|
|
$meta->{private} ? do { |
|
1260
|
7
|
|
|
|
|
20
|
push @tests, ['eval', qq|\$obj->$name|, 'private method|private attribute']; |
|
1261
|
46
|
100
|
|
|
|
158
|
} : do { |
|
1262
|
39
|
100
|
66
|
|
|
481
|
push @tests, ['is', qq|\$obj->$name|, 'undef'] if !$meta->{no_success_test} && !$meta->{builder} && !$meta->{required} && !$meta->{default}; |
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
1263
|
39
|
|
100
|
|
|
319
|
my (@test_cases) = $self->build_test_data($meta->{type}->[0] || 'Any', $name, $meta->{required} || $meta->{builder}); |
|
|
|
|
100
|
|
|
|
|
|
1264
|
39
|
100
|
|
|
|
2754
|
if (scalar @test_cases > 1) { |
|
1265
|
35
|
|
|
|
|
89
|
my $valid = shift @test_cases; |
|
1266
|
35
|
50
|
|
|
|
282
|
push @tests, ['deep', qq|\$obj->$name($valid)|, $valid] unless $meta->{no_success_test}; |
|
1267
|
35
|
50
|
|
|
|
128
|
unless ($meta->{coerce}) { |
|
1268
|
35
|
|
|
|
|
97
|
for (@test_cases) { |
|
1269
|
291
|
|
|
|
|
755
|
push @tests, ['eval', qq|\$obj->$name($_)|, 'invalid|value|type|constraint|greater|atleast' ]; |
|
1270
|
|
|
|
|
|
|
} |
|
1271
|
|
|
|
|
|
|
} |
|
1272
|
35
|
50
|
|
|
|
225
|
push @tests, ['deep', qq|\$obj->$name|, $valid] unless $meta->{no_success_test}; |
|
1273
|
|
|
|
|
|
|
} |
|
1274
|
|
|
|
|
|
|
}; |
|
1275
|
105
|
100
|
|
|
|
483
|
} : do { |
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
1276
|
|
|
|
|
|
|
$meta->{private} ? do { |
|
1277
|
0
|
|
|
|
|
0
|
push @tests, ['eval', qq|\$obj->$name|, 'private method']; |
|
1278
|
23
|
50
|
66
|
|
|
97
|
} : $meta->{param} && do { |
|
1279
|
|
|
|
|
|
|
my %test_data = map { |
|
1280
|
|
|
|
|
|
|
$_ => [ |
|
1281
|
|
|
|
|
|
|
$self->build_test_data($meta->{params_map}->{$_}->{type} || 'Any', $name), ($meta->{params_map}->{$_}->{type} || 'Any') !~ m/^(|Optional|Any|Item)/ ? q|undef| : () |
|
1282
|
|
|
|
|
|
|
] |
|
1283
|
|
|
|
|
|
|
} @{ $meta->{param} }; |
|
1284
|
|
|
|
|
|
|
for my $key (@{$meta->{param}}) { |
|
1285
|
|
|
|
|
|
|
for my $ah (splice @{$test_data{$key}}, 1) { |
|
1286
|
|
|
|
|
|
|
push @tests, [ |
|
1287
|
|
|
|
|
|
|
'eval', |
|
1288
|
|
|
|
|
|
|
sprintf( |
|
1289
|
|
|
|
|
|
|
q|$obj->%s(%s)|, |
|
1290
|
|
|
|
|
|
|
$name, |
|
1291
|
|
|
|
|
|
|
join ', ', map {$key eq $_ ? $ah : $test_data{$_}->[0]} @{$meta->{param}} |
|
1292
|
|
|
|
|
|
|
), |
|
1293
|
|
|
|
|
|
|
'invalid|value|type|constraint|greater|atleast' |
|
1294
|
|
|
|
|
|
|
]; |
|
1295
|
|
|
|
|
|
|
} |
|
1296
|
|
|
|
|
|
|
} |
|
1297
|
|
|
|
|
|
|
} |
|
1298
|
|
|
|
|
|
|
}; |
|
1299
|
105
|
100
|
|
|
|
347
|
push @tests, @{$meta->{test}} if $meta->{test}; |
|
|
2
|
|
|
|
|
7
|
|
|
1300
|
105
|
|
|
|
|
766
|
return @tests; |
|
1301
|
|
|
|
|
|
|
} |
|
1302
|
|
|
|
|
|
|
|
|
1303
|
|
|
|
|
|
|
sub _read_file { |
|
1304
|
0
|
|
|
0
|
|
0
|
my ($file) = @_; |
|
1305
|
0
|
|
|
|
|
0
|
open my $fh, '<', $file; |
|
1306
|
0
|
|
|
|
|
0
|
my $content = do { local $/; <$fh>; }; |
|
|
0
|
|
|
|
|
0
|
|
|
|
0
|
|
|
|
|
0
|
|
|
1307
|
0
|
|
|
|
|
0
|
close $fh; |
|
1308
|
0
|
|
|
|
|
0
|
return $content; |
|
1309
|
|
|
|
|
|
|
} |
|
1310
|
|
|
|
|
|
|
|
|
1311
|
|
|
|
|
|
|
sub _generate_test_string { |
|
1312
|
266
|
|
|
266
|
|
891
|
my @data = qw/penthos curae nosoi geras phobos limos aporia thanatos algea hypnos gaudia/; |
|
1313
|
266
|
|
|
|
|
2903
|
return sprintf q|'%s'|, $data[int(rand(scalar @data))]; |
|
1314
|
|
|
|
|
|
|
} |
|
1315
|
|
|
|
|
|
|
|
|
1316
|
|
|
|
|
|
|
1; |
|
1317
|
|
|
|
|
|
|
|
|
1318
|
|
|
|
|
|
|
__END__ |
|
1319
|
|
|
|
|
|
|
|
|
1320
|
|
|
|
|
|
|
=head1 NAME |
|
1321
|
|
|
|
|
|
|
|
|
1322
|
|
|
|
|
|
|
Hades - Less is more, more is less! |
|
1323
|
|
|
|
|
|
|
|
|
1324
|
|
|
|
|
|
|
=head1 VERSION |
|
1325
|
|
|
|
|
|
|
|
|
1326
|
|
|
|
|
|
|
Version 0.20 |
|
1327
|
|
|
|
|
|
|
|
|
1328
|
|
|
|
|
|
|
=cut |
|
1329
|
|
|
|
|
|
|
|
|
1330
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
1331
|
|
|
|
|
|
|
|
|
1332
|
|
|
|
|
|
|
use Hades; |
|
1333
|
|
|
|
|
|
|
|
|
1334
|
|
|
|
|
|
|
Hades->run({ |
|
1335
|
|
|
|
|
|
|
eval => q| |
|
1336
|
|
|
|
|
|
|
Kosmos { |
|
1337
|
|
|
|
|
|
|
[penthos curae] :t(Int) :d(2) :p :pr :c :r |
|
1338
|
|
|
|
|
|
|
geras $nosoi :t(Int) :d(2) { |
|
1339
|
|
|
|
|
|
|
if (£penthos == $nosoi) { |
|
1340
|
|
|
|
|
|
|
return £curae; |
|
1341
|
|
|
|
|
|
|
} |
|
1342
|
|
|
|
|
|
|
} |
|
1343
|
|
|
|
|
|
|
} |
|
1344
|
|
|
|
|
|
|
| |
|
1345
|
|
|
|
|
|
|
}); |
|
1346
|
|
|
|
|
|
|
|
|
1347
|
|
|
|
|
|
|
... generates ... |
|
1348
|
|
|
|
|
|
|
|
|
1349
|
|
|
|
|
|
|
package Kosmos; |
|
1350
|
|
|
|
|
|
|
use strict; |
|
1351
|
|
|
|
|
|
|
use warnings; |
|
1352
|
|
|
|
|
|
|
our $VERSION = 0.01; |
|
1353
|
|
|
|
|
|
|
|
|
1354
|
|
|
|
|
|
|
sub new { |
|
1355
|
|
|
|
|
|
|
my ( $cls, %args ) = ( shift(), scalar @_ == 1 ? %{ $_[0] } : @_ ); |
|
1356
|
|
|
|
|
|
|
my $self = bless {}, $cls; |
|
1357
|
|
|
|
|
|
|
my %accessors = ( |
|
1358
|
|
|
|
|
|
|
penthos => { required => 1, default => 2, }, |
|
1359
|
|
|
|
|
|
|
curae => { required => 1, default => 2, }, |
|
1360
|
|
|
|
|
|
|
); |
|
1361
|
|
|
|
|
|
|
for my $accessor ( keys %accessors ) { |
|
1362
|
|
|
|
|
|
|
my $value |
|
1363
|
|
|
|
|
|
|
= $self->$accessor( |
|
1364
|
|
|
|
|
|
|
defined $args{$accessor} |
|
1365
|
|
|
|
|
|
|
? $args{$accessor} |
|
1366
|
|
|
|
|
|
|
: $accessors{$accessor}->{default} ); |
|
1367
|
|
|
|
|
|
|
unless ( !$accessors{$accessor}->{required} || defined $value ) { |
|
1368
|
|
|
|
|
|
|
die "$accessor accessor is required"; |
|
1369
|
|
|
|
|
|
|
} |
|
1370
|
|
|
|
|
|
|
} |
|
1371
|
|
|
|
|
|
|
return $self; |
|
1372
|
|
|
|
|
|
|
} |
|
1373
|
|
|
|
|
|
|
|
|
1374
|
|
|
|
|
|
|
sub penthos { |
|
1375
|
|
|
|
|
|
|
my ( $self, $value ) = @_; |
|
1376
|
|
|
|
|
|
|
my $private_caller = caller(); |
|
1377
|
|
|
|
|
|
|
if ( $private_caller ne __PACKAGE__ ) { |
|
1378
|
|
|
|
|
|
|
die "cannot call private method penthos from $private_caller"; |
|
1379
|
|
|
|
|
|
|
} |
|
1380
|
|
|
|
|
|
|
if ( defined $value ) { |
|
1381
|
|
|
|
|
|
|
if ( ref $value || $value !~ m/^[-+\d]\d*$/ ) { |
|
1382
|
|
|
|
|
|
|
die qq{Int: invalid value $value for accessor penthos}; |
|
1383
|
|
|
|
|
|
|
} |
|
1384
|
|
|
|
|
|
|
$self->{penthos} = $value; |
|
1385
|
|
|
|
|
|
|
} |
|
1386
|
|
|
|
|
|
|
return $self->{penthos}; |
|
1387
|
|
|
|
|
|
|
} |
|
1388
|
|
|
|
|
|
|
|
|
1389
|
|
|
|
|
|
|
sub clear_penthos { |
|
1390
|
|
|
|
|
|
|
my ($self) = @_; |
|
1391
|
|
|
|
|
|
|
delete $self->{penthos}; |
|
1392
|
|
|
|
|
|
|
return $self; |
|
1393
|
|
|
|
|
|
|
} |
|
1394
|
|
|
|
|
|
|
|
|
1395
|
|
|
|
|
|
|
sub has_penthos { |
|
1396
|
|
|
|
|
|
|
my ($self) = @_; |
|
1397
|
|
|
|
|
|
|
return exists $self->{penthos}; |
|
1398
|
|
|
|
|
|
|
} |
|
1399
|
|
|
|
|
|
|
|
|
1400
|
|
|
|
|
|
|
sub curae { |
|
1401
|
|
|
|
|
|
|
my ( $self, $value ) = @_; |
|
1402
|
|
|
|
|
|
|
my $private_caller = caller(); |
|
1403
|
|
|
|
|
|
|
if ( $private_caller ne __PACKAGE__ ) { |
|
1404
|
|
|
|
|
|
|
die "cannot call private method curae from $private_caller"; |
|
1405
|
|
|
|
|
|
|
} |
|
1406
|
|
|
|
|
|
|
if ( defined $value ) { |
|
1407
|
|
|
|
|
|
|
if ( ref $value || $value !~ m/^[-+\d]\d*$/ ) { |
|
1408
|
|
|
|
|
|
|
die qq{Int: invalid value $value for accessor curae}; |
|
1409
|
|
|
|
|
|
|
} |
|
1410
|
|
|
|
|
|
|
$self->{curae} = $value; |
|
1411
|
|
|
|
|
|
|
} |
|
1412
|
|
|
|
|
|
|
return $self->{curae}; |
|
1413
|
|
|
|
|
|
|
} |
|
1414
|
|
|
|
|
|
|
|
|
1415
|
|
|
|
|
|
|
sub clear_curae { |
|
1416
|
|
|
|
|
|
|
my ($self) = @_; |
|
1417
|
|
|
|
|
|
|
delete $self->{curae}; |
|
1418
|
|
|
|
|
|
|
return $self; |
|
1419
|
|
|
|
|
|
|
} |
|
1420
|
|
|
|
|
|
|
|
|
1421
|
|
|
|
|
|
|
sub has_curae { |
|
1422
|
|
|
|
|
|
|
my ($self) = @_; |
|
1423
|
|
|
|
|
|
|
return exists $self->{curae}; |
|
1424
|
|
|
|
|
|
|
} |
|
1425
|
|
|
|
|
|
|
|
|
1426
|
|
|
|
|
|
|
sub geras { |
|
1427
|
|
|
|
|
|
|
my ( $self, $nosoi ) = @_; |
|
1428
|
|
|
|
|
|
|
$nosoi = defined $nosoi ? $nosoi : 5; |
|
1429
|
|
|
|
|
|
|
if ( !defined($nosoi) || ref $nosoi || $nosoi !~ m/^[-+\d]\d*$/ ) { |
|
1430
|
|
|
|
|
|
|
$nosoi = defined $nosoi ? $nosoi : 'undef'; |
|
1431
|
|
|
|
|
|
|
die |
|
1432
|
|
|
|
|
|
|
qq{Int: invalid value $nosoi for variable \$nosoi in method geras}; |
|
1433
|
|
|
|
|
|
|
} |
|
1434
|
|
|
|
|
|
|
if ( $self->penthos == $nosoi ) { return $self->curae; } |
|
1435
|
|
|
|
|
|
|
} |
|
1436
|
|
|
|
|
|
|
|
|
1437
|
|
|
|
|
|
|
1; |
|
1438
|
|
|
|
|
|
|
|
|
1439
|
|
|
|
|
|
|
__END__ |
|
1440
|
|
|
|
|
|
|
|
|
1441
|
|
|
|
|
|
|
=head1 SUBROUTINES/METHODS |
|
1442
|
|
|
|
|
|
|
|
|
1443
|
|
|
|
|
|
|
=head2 run |
|
1444
|
|
|
|
|
|
|
|
|
1445
|
|
|
|
|
|
|
=over |
|
1446
|
|
|
|
|
|
|
|
|
1447
|
|
|
|
|
|
|
=item file |
|
1448
|
|
|
|
|
|
|
|
|
1449
|
|
|
|
|
|
|
Provide a file to read in. |
|
1450
|
|
|
|
|
|
|
|
|
1451
|
|
|
|
|
|
|
=item eval |
|
1452
|
|
|
|
|
|
|
|
|
1453
|
|
|
|
|
|
|
Provide a string to eval. |
|
1454
|
|
|
|
|
|
|
|
|
1455
|
|
|
|
|
|
|
=item verbose |
|
1456
|
|
|
|
|
|
|
|
|
1457
|
|
|
|
|
|
|
Set verbose to true, to print build steps to STDOUT. |
|
1458
|
|
|
|
|
|
|
|
|
1459
|
|
|
|
|
|
|
=item debug |
|
1460
|
|
|
|
|
|
|
|
|
1461
|
|
|
|
|
|
|
Set debug to true, to step through the build. |
|
1462
|
|
|
|
|
|
|
|
|
1463
|
|
|
|
|
|
|
=item dist |
|
1464
|
|
|
|
|
|
|
|
|
1465
|
|
|
|
|
|
|
Provide a name for the distribution. |
|
1466
|
|
|
|
|
|
|
|
|
1467
|
|
|
|
|
|
|
=item lib |
|
1468
|
|
|
|
|
|
|
|
|
1469
|
|
|
|
|
|
|
Provide a path where the generated files will be compiled. |
|
1470
|
|
|
|
|
|
|
|
|
1471
|
|
|
|
|
|
|
=item tlib |
|
1472
|
|
|
|
|
|
|
|
|
1473
|
|
|
|
|
|
|
Provide a path where the generates test files will be compiled. |
|
1474
|
|
|
|
|
|
|
|
|
1475
|
|
|
|
|
|
|
=item author |
|
1476
|
|
|
|
|
|
|
|
|
1477
|
|
|
|
|
|
|
The author of the distribution/module. |
|
1478
|
|
|
|
|
|
|
|
|
1479
|
|
|
|
|
|
|
=item email |
|
1480
|
|
|
|
|
|
|
|
|
1481
|
|
|
|
|
|
|
The authors email of the distribution/module. |
|
1482
|
|
|
|
|
|
|
|
|
1483
|
|
|
|
|
|
|
=item version |
|
1484
|
|
|
|
|
|
|
|
|
1485
|
|
|
|
|
|
|
The version number of the distribution/module. |
|
1486
|
|
|
|
|
|
|
|
|
1487
|
|
|
|
|
|
|
=item realm |
|
1488
|
|
|
|
|
|
|
|
|
1489
|
|
|
|
|
|
|
The Hades realm that is used to generate the code. |
|
1490
|
|
|
|
|
|
|
|
|
1491
|
|
|
|
|
|
|
=cut |
|
1492
|
|
|
|
|
|
|
|
|
1493
|
|
|
|
|
|
|
=back |
|
1494
|
|
|
|
|
|
|
|
|
1495
|
|
|
|
|
|
|
=head1 Hades |
|
1496
|
|
|
|
|
|
|
|
|
1497
|
|
|
|
|
|
|
=cut |
|
1498
|
|
|
|
|
|
|
|
|
1499
|
|
|
|
|
|
|
=head2 Class |
|
1500
|
|
|
|
|
|
|
|
|
1501
|
|
|
|
|
|
|
Declare a new class. |
|
1502
|
|
|
|
|
|
|
|
|
1503
|
|
|
|
|
|
|
Kosmos { |
|
1504
|
|
|
|
|
|
|
|
|
1505
|
|
|
|
|
|
|
} |
|
1506
|
|
|
|
|
|
|
|
|
1507
|
|
|
|
|
|
|
=cut |
|
1508
|
|
|
|
|
|
|
|
|
1509
|
|
|
|
|
|
|
=head3 Abstract |
|
1510
|
|
|
|
|
|
|
|
|
1511
|
|
|
|
|
|
|
Declare the classes Abstract. |
|
1512
|
|
|
|
|
|
|
|
|
1513
|
|
|
|
|
|
|
Kosmos { |
|
1514
|
|
|
|
|
|
|
abstract { Afti einai i perilipsi } |
|
1515
|
|
|
|
|
|
|
} |
|
1516
|
|
|
|
|
|
|
|
|
1517
|
|
|
|
|
|
|
=cut |
|
1518
|
|
|
|
|
|
|
|
|
1519
|
|
|
|
|
|
|
=head3 Synopsis |
|
1520
|
|
|
|
|
|
|
|
|
1521
|
|
|
|
|
|
|
Declare the classes Synopsis. |
|
1522
|
|
|
|
|
|
|
|
|
1523
|
|
|
|
|
|
|
Kosmos { |
|
1524
|
|
|
|
|
|
|
synopsis { |
|
1525
|
|
|
|
|
|
|
Schetika me ton Kosmos |
|
1526
|
|
|
|
|
|
|
|
|
1527
|
|
|
|
|
|
|
Kosmos->new; |
|
1528
|
|
|
|
|
|
|
} |
|
1529
|
|
|
|
|
|
|
} |
|
1530
|
|
|
|
|
|
|
|
|
1531
|
|
|
|
|
|
|
=cut |
|
1532
|
|
|
|
|
|
|
|
|
1533
|
|
|
|
|
|
|
=head3 Inheritance |
|
1534
|
|
|
|
|
|
|
|
|
1535
|
|
|
|
|
|
|
=cut |
|
1536
|
|
|
|
|
|
|
|
|
1537
|
|
|
|
|
|
|
=head4 base |
|
1538
|
|
|
|
|
|
|
|
|
1539
|
|
|
|
|
|
|
Establish an ISA relationship with base classes at compile time. |
|
1540
|
|
|
|
|
|
|
|
|
1541
|
|
|
|
|
|
|
Unless you are using the fields pragma, consider this discouraged in favor of the lighter-weight parent. |
|
1542
|
|
|
|
|
|
|
|
|
1543
|
|
|
|
|
|
|
Kosmos base Kato { |
|
1544
|
|
|
|
|
|
|
|
|
1545
|
|
|
|
|
|
|
} |
|
1546
|
|
|
|
|
|
|
|
|
1547
|
|
|
|
|
|
|
=cut |
|
1548
|
|
|
|
|
|
|
|
|
1549
|
|
|
|
|
|
|
=head4 parent |
|
1550
|
|
|
|
|
|
|
|
|
1551
|
|
|
|
|
|
|
Establish an ISA relationship with base classes at compile time. |
|
1552
|
|
|
|
|
|
|
|
|
1553
|
|
|
|
|
|
|
Kosmos parent Kato { |
|
1554
|
|
|
|
|
|
|
|
|
1555
|
|
|
|
|
|
|
} |
|
1556
|
|
|
|
|
|
|
|
|
1557
|
|
|
|
|
|
|
=cut |
|
1558
|
|
|
|
|
|
|
|
|
1559
|
|
|
|
|
|
|
=head4 require |
|
1560
|
|
|
|
|
|
|
|
|
1561
|
|
|
|
|
|
|
Require library files to be included if they have not already been included. |
|
1562
|
|
|
|
|
|
|
|
|
1563
|
|
|
|
|
|
|
Kosmos require Kato { |
|
1564
|
|
|
|
|
|
|
|
|
1565
|
|
|
|
|
|
|
} |
|
1566
|
|
|
|
|
|
|
|
|
1567
|
|
|
|
|
|
|
=cut |
|
1568
|
|
|
|
|
|
|
|
|
1569
|
|
|
|
|
|
|
=head4 use |
|
1570
|
|
|
|
|
|
|
|
|
1571
|
|
|
|
|
|
|
Declare modules that should be included in the class. |
|
1572
|
|
|
|
|
|
|
|
|
1573
|
|
|
|
|
|
|
Kosmos use Kato Vathys { |
|
1574
|
|
|
|
|
|
|
|
|
1575
|
|
|
|
|
|
|
} |
|
1576
|
|
|
|
|
|
|
|
|
1577
|
|
|
|
|
|
|
=cut |
|
1578
|
|
|
|
|
|
|
|
|
1579
|
|
|
|
|
|
|
=head3 Test |
|
1580
|
|
|
|
|
|
|
|
|
1581
|
|
|
|
|
|
|
Declare the classes additional tests. |
|
1582
|
|
|
|
|
|
|
|
|
1583
|
|
|
|
|
|
|
Kosmos { |
|
1584
|
|
|
|
|
|
|
test { |
|
1585
|
|
|
|
|
|
|
[ |
|
1586
|
|
|
|
|
|
|
['ok', 'my $obj = Kosmos->new'], |
|
1587
|
|
|
|
|
|
|
['is', '$obj->dokimi', undef] |
|
1588
|
|
|
|
|
|
|
] |
|
1589
|
|
|
|
|
|
|
} |
|
1590
|
|
|
|
|
|
|
} |
|
1591
|
|
|
|
|
|
|
|
|
1592
|
|
|
|
|
|
|
=cut |
|
1593
|
|
|
|
|
|
|
|
|
1594
|
|
|
|
|
|
|
=head2 Compile phase |
|
1595
|
|
|
|
|
|
|
|
|
1596
|
|
|
|
|
|
|
=cut |
|
1597
|
|
|
|
|
|
|
|
|
1598
|
|
|
|
|
|
|
=head3 begin |
|
1599
|
|
|
|
|
|
|
|
|
1600
|
|
|
|
|
|
|
Define a code block is executed as soon as possible. |
|
1601
|
|
|
|
|
|
|
|
|
1602
|
|
|
|
|
|
|
Kosmos { |
|
1603
|
|
|
|
|
|
|
begin { |
|
1604
|
|
|
|
|
|
|
... perl code ... |
|
1605
|
|
|
|
|
|
|
} |
|
1606
|
|
|
|
|
|
|
} |
|
1607
|
|
|
|
|
|
|
|
|
1608
|
|
|
|
|
|
|
=cut |
|
1609
|
|
|
|
|
|
|
|
|
1610
|
|
|
|
|
|
|
=head3 unitcheck |
|
1611
|
|
|
|
|
|
|
|
|
1612
|
|
|
|
|
|
|
Define a code block that is executed just after the unit which defined them has been compiled. |
|
1613
|
|
|
|
|
|
|
|
|
1614
|
|
|
|
|
|
|
Kosmos { |
|
1615
|
|
|
|
|
|
|
unitcheck { |
|
1616
|
|
|
|
|
|
|
... perl code ... |
|
1617
|
|
|
|
|
|
|
} |
|
1618
|
|
|
|
|
|
|
} |
|
1619
|
|
|
|
|
|
|
|
|
1620
|
|
|
|
|
|
|
=cut |
|
1621
|
|
|
|
|
|
|
|
|
1622
|
|
|
|
|
|
|
=head3 check |
|
1623
|
|
|
|
|
|
|
|
|
1624
|
|
|
|
|
|
|
Define a code block that is executed just after the initial Perl compile phase ends and before the run time begins. |
|
1625
|
|
|
|
|
|
|
|
|
1626
|
|
|
|
|
|
|
Kosmos { |
|
1627
|
|
|
|
|
|
|
check { |
|
1628
|
|
|
|
|
|
|
... perl code ... |
|
1629
|
|
|
|
|
|
|
} |
|
1630
|
|
|
|
|
|
|
} |
|
1631
|
|
|
|
|
|
|
|
|
1632
|
|
|
|
|
|
|
=cut |
|
1633
|
|
|
|
|
|
|
|
|
1634
|
|
|
|
|
|
|
=head3 init |
|
1635
|
|
|
|
|
|
|
|
|
1636
|
|
|
|
|
|
|
Define a code block that is executed just before the Perl runtime begins execution. |
|
1637
|
|
|
|
|
|
|
|
|
1638
|
|
|
|
|
|
|
Kosmos { |
|
1639
|
|
|
|
|
|
|
init { |
|
1640
|
|
|
|
|
|
|
... perl code ... |
|
1641
|
|
|
|
|
|
|
} |
|
1642
|
|
|
|
|
|
|
} |
|
1643
|
|
|
|
|
|
|
|
|
1644
|
|
|
|
|
|
|
=cut |
|
1645
|
|
|
|
|
|
|
|
|
1646
|
|
|
|
|
|
|
=head3 end |
|
1647
|
|
|
|
|
|
|
|
|
1648
|
|
|
|
|
|
|
Define a code block is executed as late as possible. |
|
1649
|
|
|
|
|
|
|
|
|
1650
|
|
|
|
|
|
|
Kosmos { |
|
1651
|
|
|
|
|
|
|
end { |
|
1652
|
|
|
|
|
|
|
... perl code ... |
|
1653
|
|
|
|
|
|
|
} |
|
1654
|
|
|
|
|
|
|
} |
|
1655
|
|
|
|
|
|
|
|
|
1656
|
|
|
|
|
|
|
=cut |
|
1657
|
|
|
|
|
|
|
|
|
1658
|
|
|
|
|
|
|
=head2 Variables |
|
1659
|
|
|
|
|
|
|
|
|
1660
|
|
|
|
|
|
|
=cut |
|
1661
|
|
|
|
|
|
|
|
|
1662
|
|
|
|
|
|
|
=head3 our |
|
1663
|
|
|
|
|
|
|
|
|
1664
|
|
|
|
|
|
|
Declare variable of the same name in the current package for use within the lexical scope. |
|
1665
|
|
|
|
|
|
|
|
|
1666
|
|
|
|
|
|
|
Kosmos { |
|
1667
|
|
|
|
|
|
|
our $one %two |
|
1668
|
|
|
|
|
|
|
} |
|
1669
|
|
|
|
|
|
|
|
|
1670
|
|
|
|
|
|
|
=cut |
|
1671
|
|
|
|
|
|
|
|
|
1672
|
|
|
|
|
|
|
=head2 Accessors |
|
1673
|
|
|
|
|
|
|
|
|
1674
|
|
|
|
|
|
|
Declare an accessor for the class |
|
1675
|
|
|
|
|
|
|
|
|
1676
|
|
|
|
|
|
|
Kosmos { |
|
1677
|
|
|
|
|
|
|
dokimi |
|
1678
|
|
|
|
|
|
|
dokimes |
|
1679
|
|
|
|
|
|
|
} |
|
1680
|
|
|
|
|
|
|
|
|
1681
|
|
|
|
|
|
|
=cut |
|
1682
|
|
|
|
|
|
|
|
|
1683
|
|
|
|
|
|
|
=head3 :required | :r |
|
1684
|
|
|
|
|
|
|
|
|
1685
|
|
|
|
|
|
|
Making an accessor required means a value for the accessor must be supplied to the constructor. |
|
1686
|
|
|
|
|
|
|
|
|
1687
|
|
|
|
|
|
|
dokimi :r |
|
1688
|
|
|
|
|
|
|
dokimes :required |
|
1689
|
|
|
|
|
|
|
|
|
1690
|
|
|
|
|
|
|
=cut |
|
1691
|
|
|
|
|
|
|
|
|
1692
|
|
|
|
|
|
|
=head3 :default | :d |
|
1693
|
|
|
|
|
|
|
|
|
1694
|
|
|
|
|
|
|
The default is used when no value for the accessor was supplied to the constructor. |
|
1695
|
|
|
|
|
|
|
|
|
1696
|
|
|
|
|
|
|
dokimi :d(Eimai o monos) |
|
1697
|
|
|
|
|
|
|
dokimes :default([{ ola => "peripou", o => [qw/kosmos/] }]) |
|
1698
|
|
|
|
|
|
|
|
|
1699
|
|
|
|
|
|
|
=cut |
|
1700
|
|
|
|
|
|
|
|
|
1701
|
|
|
|
|
|
|
=head3 :clearer | :c |
|
1702
|
|
|
|
|
|
|
|
|
1703
|
|
|
|
|
|
|
Setting clearer creates a method to clear the accessor. |
|
1704
|
|
|
|
|
|
|
|
|
1705
|
|
|
|
|
|
|
dokimi :c |
|
1706
|
|
|
|
|
|
|
dokimes :clearer |
|
1707
|
|
|
|
|
|
|
|
|
1708
|
|
|
|
|
|
|
$class->clear_dokimi; |
|
1709
|
|
|
|
|
|
|
|
|
1710
|
|
|
|
|
|
|
=cut |
|
1711
|
|
|
|
|
|
|
|
|
1712
|
|
|
|
|
|
|
=head3 :coerce | :co |
|
1713
|
|
|
|
|
|
|
|
|
1714
|
|
|
|
|
|
|
Takes a coderef which is meant to coerce the attributes value. |
|
1715
|
|
|
|
|
|
|
|
|
1716
|
|
|
|
|
|
|
dokimi :co(array_to_string) |
|
1717
|
|
|
|
|
|
|
dokimes :coerce($value = $value->[0] if ref($value) || "" eq "ARRAY";) |
|
1718
|
|
|
|
|
|
|
|
|
1719
|
|
|
|
|
|
|
=cut |
|
1720
|
|
|
|
|
|
|
|
|
1721
|
|
|
|
|
|
|
=head3 :private | :p |
|
1722
|
|
|
|
|
|
|
|
|
1723
|
|
|
|
|
|
|
Setting private makes the accessor only available to the class. |
|
1724
|
|
|
|
|
|
|
|
|
1725
|
|
|
|
|
|
|
dokimi :p |
|
1726
|
|
|
|
|
|
|
dokimes :private |
|
1727
|
|
|
|
|
|
|
|
|
1728
|
|
|
|
|
|
|
=cut |
|
1729
|
|
|
|
|
|
|
|
|
1730
|
|
|
|
|
|
|
=head3 :predicate | :pr |
|
1731
|
|
|
|
|
|
|
|
|
1732
|
|
|
|
|
|
|
Takes a method name which will return true if an attribute has a value. The predicate is automatically named has_${accessor}. |
|
1733
|
|
|
|
|
|
|
|
|
1734
|
|
|
|
|
|
|
dokimi :pr |
|
1735
|
|
|
|
|
|
|
dokimes :predicate |
|
1736
|
|
|
|
|
|
|
|
|
1737
|
|
|
|
|
|
|
=cut |
|
1738
|
|
|
|
|
|
|
|
|
1739
|
|
|
|
|
|
|
=head3 :trigger | :tr |
|
1740
|
|
|
|
|
|
|
|
|
1741
|
|
|
|
|
|
|
Takes a coderef which will get called any time the attribute is set. |
|
1742
|
|
|
|
|
|
|
|
|
1743
|
|
|
|
|
|
|
dokimi :tr(trigger_to_method) |
|
1744
|
|
|
|
|
|
|
dokimes :trigger(warn Dumper $value) |
|
1745
|
|
|
|
|
|
|
|
|
1746
|
|
|
|
|
|
|
=cut |
|
1747
|
|
|
|
|
|
|
|
|
1748
|
|
|
|
|
|
|
=head3 :type | :t |
|
1749
|
|
|
|
|
|
|
|
|
1750
|
|
|
|
|
|
|
Add type checking to the accessor. |
|
1751
|
|
|
|
|
|
|
|
|
1752
|
|
|
|
|
|
|
dokimi :t(Dict[onoma => Str, id => Optional[Int], epiloges => Dict[onama => Str]]) |
|
1753
|
|
|
|
|
|
|
dokimes :type(Str) |
|
1754
|
|
|
|
|
|
|
|
|
1755
|
|
|
|
|
|
|
=cut |
|
1756
|
|
|
|
|
|
|
|
|
1757
|
|
|
|
|
|
|
=head3 :builder | :bdr |
|
1758
|
|
|
|
|
|
|
|
|
1759
|
|
|
|
|
|
|
Takes a coderef which is meant to build the attributes value. |
|
1760
|
|
|
|
|
|
|
|
|
1761
|
|
|
|
|
|
|
dokimi :bdr |
|
1762
|
|
|
|
|
|
|
dokimes :builder($value = $value->[0] if ref($value) || "" eq "ARRAY";) |
|
1763
|
|
|
|
|
|
|
|
|
1764
|
|
|
|
|
|
|
=cut |
|
1765
|
|
|
|
|
|
|
|
|
1766
|
|
|
|
|
|
|
=head3 :test | :z |
|
1767
|
|
|
|
|
|
|
|
|
1768
|
|
|
|
|
|
|
Add tests associated to the accessor. |
|
1769
|
|
|
|
|
|
|
|
|
1770
|
|
|
|
|
|
|
dokimi :z(['ok', '$obj->dokimi']) |
|
1771
|
|
|
|
|
|
|
dokimes :z(['deep', '$obj->dokimes({})', q|{}|) |
|
1772
|
|
|
|
|
|
|
|
|
1773
|
|
|
|
|
|
|
=cut |
|
1774
|
|
|
|
|
|
|
|
|
1775
|
|
|
|
|
|
|
=head2 Methods |
|
1776
|
|
|
|
|
|
|
|
|
1777
|
|
|
|
|
|
|
Declare a sub routine/method. |
|
1778
|
|
|
|
|
|
|
|
|
1779
|
|
|
|
|
|
|
Kosmos { |
|
1780
|
|
|
|
|
|
|
dokimi { |
|
1781
|
|
|
|
|
|
|
... perl code ... |
|
1782
|
|
|
|
|
|
|
} |
|
1783
|
|
|
|
|
|
|
} |
|
1784
|
|
|
|
|
|
|
|
|
1785
|
|
|
|
|
|
|
=head3 Params |
|
1786
|
|
|
|
|
|
|
|
|
1787
|
|
|
|
|
|
|
Methods will always have $self defined but you can define additional params by declaring them before the code block. |
|
1788
|
|
|
|
|
|
|
|
|
1789
|
|
|
|
|
|
|
dokimi $one %two { |
|
1790
|
|
|
|
|
|
|
... perl code ... |
|
1791
|
|
|
|
|
|
|
} |
|
1792
|
|
|
|
|
|
|
|
|
1793
|
|
|
|
|
|
|
generates |
|
1794
|
|
|
|
|
|
|
|
|
1795
|
|
|
|
|
|
|
sub dokimi { |
|
1796
|
|
|
|
|
|
|
my ($self, $one, %two) = @_; |
|
1797
|
|
|
|
|
|
|
... perl code ... |
|
1798
|
|
|
|
|
|
|
} |
|
1799
|
|
|
|
|
|
|
|
|
1800
|
|
|
|
|
|
|
=cut |
|
1801
|
|
|
|
|
|
|
|
|
1802
|
|
|
|
|
|
|
=head4 :type :t |
|
1803
|
|
|
|
|
|
|
|
|
1804
|
|
|
|
|
|
|
Add type checking to the param. |
|
1805
|
|
|
|
|
|
|
|
|
1806
|
|
|
|
|
|
|
dokimi $one :t(Str) { |
|
1807
|
|
|
|
|
|
|
... perl code ... |
|
1808
|
|
|
|
|
|
|
} |
|
1809
|
|
|
|
|
|
|
|
|
1810
|
|
|
|
|
|
|
dokimes $one :t(Str) $two :t(HashRef) { |
|
1811
|
|
|
|
|
|
|
... perl code ... |
|
1812
|
|
|
|
|
|
|
} |
|
1813
|
|
|
|
|
|
|
=cut |
|
1814
|
|
|
|
|
|
|
|
|
1815
|
|
|
|
|
|
|
=head4 :coerce | :co |
|
1816
|
|
|
|
|
|
|
|
|
1817
|
|
|
|
|
|
|
Takes a coderef which is meant to coerce the method param. |
|
1818
|
|
|
|
|
|
|
|
|
1819
|
|
|
|
|
|
|
dokimi $str :co(array_to_string) |
|
1820
|
|
|
|
|
|
|
dokimes $str :t(Str) :co(array_to_string) |
|
1821
|
|
|
|
|
|
|
|
|
1822
|
|
|
|
|
|
|
=cut |
|
1823
|
|
|
|
|
|
|
|
|
1824
|
|
|
|
|
|
|
=head3 :private :p |
|
1825
|
|
|
|
|
|
|
|
|
1826
|
|
|
|
|
|
|
Setting private makes the method only available to the class. |
|
1827
|
|
|
|
|
|
|
|
|
1828
|
|
|
|
|
|
|
dokimi :p { |
|
1829
|
|
|
|
|
|
|
... perl code ... |
|
1830
|
|
|
|
|
|
|
} |
|
1831
|
|
|
|
|
|
|
dokimes :private $one %two { |
|
1832
|
|
|
|
|
|
|
... perl code ... |
|
1833
|
|
|
|
|
|
|
} |
|
1834
|
|
|
|
|
|
|
|
|
1835
|
|
|
|
|
|
|
=cut |
|
1836
|
|
|
|
|
|
|
|
|
1837
|
|
|
|
|
|
|
=head3 :default | :d |
|
1838
|
|
|
|
|
|
|
|
|
1839
|
|
|
|
|
|
|
The default is used when no value for the sub was passed as a param. |
|
1840
|
|
|
|
|
|
|
|
|
1841
|
|
|
|
|
|
|
dokimi $str :d(Eimai o monos) { } |
|
1842
|
|
|
|
|
|
|
dokimes $arrayRef :default([{ ola => "peripou", o => [qw/kosmos/] }]) { } |
|
1843
|
|
|
|
|
|
|
|
|
1844
|
|
|
|
|
|
|
=cut |
|
1845
|
|
|
|
|
|
|
|
|
1846
|
|
|
|
|
|
|
=head3 :test | :z |
|
1847
|
|
|
|
|
|
|
|
|
1848
|
|
|
|
|
|
|
Add tests associated to the sub. |
|
1849
|
|
|
|
|
|
|
|
|
1850
|
|
|
|
|
|
|
dokimi :z(['ok', '$obj->dokimi']) { } |
|
1851
|
|
|
|
|
|
|
dokimes :test(['deep', '$obj->dokimes({})', q|{}|) { } |
|
1852
|
|
|
|
|
|
|
|
|
1853
|
|
|
|
|
|
|
=cut |
|
1854
|
|
|
|
|
|
|
|
|
1855
|
|
|
|
|
|
|
=head3 :before | :b |
|
1856
|
|
|
|
|
|
|
|
|
1857
|
|
|
|
|
|
|
Before is called before the parent method is called. You can modify the params using the @params variable. |
|
1858
|
|
|
|
|
|
|
|
|
1859
|
|
|
|
|
|
|
dokimi :b { |
|
1860
|
|
|
|
|
|
|
... before ... |
|
1861
|
|
|
|
|
|
|
}: |
|
1862
|
|
|
|
|
|
|
|
|
1863
|
|
|
|
|
|
|
generates |
|
1864
|
|
|
|
|
|
|
|
|
1865
|
|
|
|
|
|
|
sub dokimi { |
|
1866
|
|
|
|
|
|
|
my ( $orig, $self, @params ) = ( 'SUPER::geras', @_ ); |
|
1867
|
|
|
|
|
|
|
... before ... |
|
1868
|
|
|
|
|
|
|
my @res = $self->$orig(@params); |
|
1869
|
|
|
|
|
|
|
return @res; |
|
1870
|
|
|
|
|
|
|
} |
|
1871
|
|
|
|
|
|
|
|
|
1872
|
|
|
|
|
|
|
=cut |
|
1873
|
|
|
|
|
|
|
|
|
1874
|
|
|
|
|
|
|
=head3 :around | :ar |
|
1875
|
|
|
|
|
|
|
|
|
1876
|
|
|
|
|
|
|
Around is called instead of the method it is modifying. The method you're overriding is passed in as the first argument (called $orig by convention). You can modify the params using the @params variable. |
|
1877
|
|
|
|
|
|
|
|
|
1878
|
|
|
|
|
|
|
dokimi :ar { |
|
1879
|
|
|
|
|
|
|
... before around ... |
|
1880
|
|
|
|
|
|
|
my @res = $self->$orig(@params); |
|
1881
|
|
|
|
|
|
|
... after around ... |
|
1882
|
|
|
|
|
|
|
} |
|
1883
|
|
|
|
|
|
|
|
|
1884
|
|
|
|
|
|
|
generates |
|
1885
|
|
|
|
|
|
|
|
|
1886
|
|
|
|
|
|
|
sub dokimi { |
|
1887
|
|
|
|
|
|
|
my ( $orig, $self, @params ) = ( 'SUPER::geras', @_ ); |
|
1888
|
|
|
|
|
|
|
... before around ... |
|
1889
|
|
|
|
|
|
|
my @res = $self->$orig(@params); |
|
1890
|
|
|
|
|
|
|
... after around ... |
|
1891
|
|
|
|
|
|
|
return @res; |
|
1892
|
|
|
|
|
|
|
} |
|
1893
|
|
|
|
|
|
|
|
|
1894
|
|
|
|
|
|
|
|
|
1895
|
|
|
|
|
|
|
=cut |
|
1896
|
|
|
|
|
|
|
|
|
1897
|
|
|
|
|
|
|
=head3 :after | :a |
|
1898
|
|
|
|
|
|
|
|
|
1899
|
|
|
|
|
|
|
After is called after the parent method is called. You can modify the response using the @res variable. |
|
1900
|
|
|
|
|
|
|
|
|
1901
|
|
|
|
|
|
|
dokimi :a { |
|
1902
|
|
|
|
|
|
|
... after ... |
|
1903
|
|
|
|
|
|
|
} |
|
1904
|
|
|
|
|
|
|
|
|
1905
|
|
|
|
|
|
|
generates |
|
1906
|
|
|
|
|
|
|
|
|
1907
|
|
|
|
|
|
|
sub dokimi { |
|
1908
|
|
|
|
|
|
|
my ( $orig, $self, @params ) = ( 'SUPER::geras', @_ ); |
|
1909
|
|
|
|
|
|
|
my @res = $self->$orig(@params); |
|
1910
|
|
|
|
|
|
|
... after ... |
|
1911
|
|
|
|
|
|
|
return @res; |
|
1912
|
|
|
|
|
|
|
} |
|
1913
|
|
|
|
|
|
|
|
|
1914
|
|
|
|
|
|
|
=cut |
|
1915
|
|
|
|
|
|
|
|
|
1916
|
|
|
|
|
|
|
=head2 Types |
|
1917
|
|
|
|
|
|
|
|
|
1918
|
|
|
|
|
|
|
=cut |
|
1919
|
|
|
|
|
|
|
|
|
1920
|
|
|
|
|
|
|
=head3 Any |
|
1921
|
|
|
|
|
|
|
|
|
1922
|
|
|
|
|
|
|
Absolutely any value passes this type constraint (even undef). |
|
1923
|
|
|
|
|
|
|
|
|
1924
|
|
|
|
|
|
|
dokimi :t(Any) |
|
1925
|
|
|
|
|
|
|
|
|
1926
|
|
|
|
|
|
|
=cut |
|
1927
|
|
|
|
|
|
|
|
|
1928
|
|
|
|
|
|
|
=head3 Item |
|
1929
|
|
|
|
|
|
|
|
|
1930
|
|
|
|
|
|
|
Essentially the same as Any. All other type constraints in this library inherit directly or indirectly from Item. |
|
1931
|
|
|
|
|
|
|
|
|
1932
|
|
|
|
|
|
|
dokimi :t(Item) |
|
1933
|
|
|
|
|
|
|
|
|
1934
|
|
|
|
|
|
|
=cut |
|
1935
|
|
|
|
|
|
|
|
|
1936
|
|
|
|
|
|
|
=head3 Bool |
|
1937
|
|
|
|
|
|
|
|
|
1938
|
|
|
|
|
|
|
Values that are reasonable booleans. Accepts 1, 0, the empty string and undef. |
|
1939
|
|
|
|
|
|
|
|
|
1940
|
|
|
|
|
|
|
dokimi :t(Bool) |
|
1941
|
|
|
|
|
|
|
|
|
1942
|
|
|
|
|
|
|
=cut |
|
1943
|
|
|
|
|
|
|
|
|
1944
|
|
|
|
|
|
|
=head3 Str |
|
1945
|
|
|
|
|
|
|
|
|
1946
|
|
|
|
|
|
|
Any string. |
|
1947
|
|
|
|
|
|
|
|
|
1948
|
|
|
|
|
|
|
dokimi :t(Str) |
|
1949
|
|
|
|
|
|
|
|
|
1950
|
|
|
|
|
|
|
=cut |
|
1951
|
|
|
|
|
|
|
|
|
1952
|
|
|
|
|
|
|
=head3 Num |
|
1953
|
|
|
|
|
|
|
|
|
1954
|
|
|
|
|
|
|
Any number. |
|
1955
|
|
|
|
|
|
|
|
|
1956
|
|
|
|
|
|
|
dokimi :t(Num) |
|
1957
|
|
|
|
|
|
|
|
|
1958
|
|
|
|
|
|
|
=cut |
|
1959
|
|
|
|
|
|
|
|
|
1960
|
|
|
|
|
|
|
=head3 Int |
|
1961
|
|
|
|
|
|
|
|
|
1962
|
|
|
|
|
|
|
An integer; that is a string of digits 0 to 9, optionally prefixed with a hyphen-minus character. |
|
1963
|
|
|
|
|
|
|
|
|
1964
|
|
|
|
|
|
|
dokimi :t(Int) |
|
1965
|
|
|
|
|
|
|
|
|
1966
|
|
|
|
|
|
|
=cut |
|
1967
|
|
|
|
|
|
|
|
|
1968
|
|
|
|
|
|
|
=head3 Ref |
|
1969
|
|
|
|
|
|
|
|
|
1970
|
|
|
|
|
|
|
Any defined reference value, including blessed objects. |
|
1971
|
|
|
|
|
|
|
|
|
1972
|
|
|
|
|
|
|
dokimi :t(Ref) |
|
1973
|
|
|
|
|
|
|
dokimes :t(Ref[HASH]) |
|
1974
|
|
|
|
|
|
|
|
|
1975
|
|
|
|
|
|
|
=cut |
|
1976
|
|
|
|
|
|
|
|
|
1977
|
|
|
|
|
|
|
=head3 ScalarRef |
|
1978
|
|
|
|
|
|
|
|
|
1979
|
|
|
|
|
|
|
A value where ref($value) eq "SCALAR" or ref($value) eq "REF". |
|
1980
|
|
|
|
|
|
|
|
|
1981
|
|
|
|
|
|
|
dokimi :t(ScalarRef) |
|
1982
|
|
|
|
|
|
|
dokimes :t(ScalarRef[SCALAR]) |
|
1983
|
|
|
|
|
|
|
|
|
1984
|
|
|
|
|
|
|
=cut |
|
1985
|
|
|
|
|
|
|
|
|
1986
|
|
|
|
|
|
|
=head3 ArrayRef |
|
1987
|
|
|
|
|
|
|
|
|
1988
|
|
|
|
|
|
|
A value where ref($value) eq "ARRAY". |
|
1989
|
|
|
|
|
|
|
|
|
1990
|
|
|
|
|
|
|
dokimi :t(ArrayRef) |
|
1991
|
|
|
|
|
|
|
dokimes :t(ArrayRef[Str, 1, 100]) |
|
1992
|
|
|
|
|
|
|
|
|
1993
|
|
|
|
|
|
|
=cut |
|
1994
|
|
|
|
|
|
|
|
|
1995
|
|
|
|
|
|
|
=head3 HashRef |
|
1996
|
|
|
|
|
|
|
|
|
1997
|
|
|
|
|
|
|
A value where ref($value) eq "HASH". |
|
1998
|
|
|
|
|
|
|
|
|
1999
|
|
|
|
|
|
|
dokimi :t(HashRef) |
|
2000
|
|
|
|
|
|
|
dokimes :t(HashRef[Int]) |
|
2001
|
|
|
|
|
|
|
|
|
2002
|
|
|
|
|
|
|
=cut |
|
2003
|
|
|
|
|
|
|
|
|
2004
|
|
|
|
|
|
|
=head3 CodeRef |
|
2005
|
|
|
|
|
|
|
|
|
2006
|
|
|
|
|
|
|
A value where ref($value) eq "CODE" |
|
2007
|
|
|
|
|
|
|
|
|
2008
|
|
|
|
|
|
|
dokimi :t(CodeRef) |
|
2009
|
|
|
|
|
|
|
|
|
2010
|
|
|
|
|
|
|
=cut |
|
2011
|
|
|
|
|
|
|
|
|
2012
|
|
|
|
|
|
|
=head3 RegexpRef |
|
2013
|
|
|
|
|
|
|
|
|
2014
|
|
|
|
|
|
|
A value where ref($value) eq "Regexp" |
|
2015
|
|
|
|
|
|
|
|
|
2016
|
|
|
|
|
|
|
dokimi :t(RegexpRef) |
|
2017
|
|
|
|
|
|
|
|
|
2018
|
|
|
|
|
|
|
=cut |
|
2019
|
|
|
|
|
|
|
|
|
2020
|
|
|
|
|
|
|
=head3 GlobRef |
|
2021
|
|
|
|
|
|
|
|
|
2022
|
|
|
|
|
|
|
A value where ref($value) eq "GLOB" |
|
2023
|
|
|
|
|
|
|
|
|
2024
|
|
|
|
|
|
|
dokimi :t(GlobRef) |
|
2025
|
|
|
|
|
|
|
|
|
2026
|
|
|
|
|
|
|
=cut |
|
2027
|
|
|
|
|
|
|
|
|
2028
|
|
|
|
|
|
|
=head3 Object |
|
2029
|
|
|
|
|
|
|
|
|
2030
|
|
|
|
|
|
|
A blessed object. |
|
2031
|
|
|
|
|
|
|
|
|
2032
|
|
|
|
|
|
|
dokimi :t(Object) |
|
2033
|
|
|
|
|
|
|
|
|
2034
|
|
|
|
|
|
|
=cut |
|
2035
|
|
|
|
|
|
|
|
|
2036
|
|
|
|
|
|
|
=head3 Map |
|
2037
|
|
|
|
|
|
|
|
|
2038
|
|
|
|
|
|
|
Similar to HashRef but parameterized with type constraints for both the key and value. The constraint for keys would typically be a subtype of Str. |
|
2039
|
|
|
|
|
|
|
|
|
2040
|
|
|
|
|
|
|
dokimi :t(Map[Str, Int]) |
|
2041
|
|
|
|
|
|
|
|
|
2042
|
|
|
|
|
|
|
=cut |
|
2043
|
|
|
|
|
|
|
|
|
2044
|
|
|
|
|
|
|
=head3 Tuple |
|
2045
|
|
|
|
|
|
|
|
|
2046
|
|
|
|
|
|
|
Accepting a list of type constraints for each slot in the array. |
|
2047
|
|
|
|
|
|
|
|
|
2048
|
|
|
|
|
|
|
dokimi :t(Tuple[Str, Int, HashRef]) |
|
2049
|
|
|
|
|
|
|
|
|
2050
|
|
|
|
|
|
|
=cut |
|
2051
|
|
|
|
|
|
|
|
|
2052
|
|
|
|
|
|
|
=head3 Dict |
|
2053
|
|
|
|
|
|
|
|
|
2054
|
|
|
|
|
|
|
Accepting a list of type constraints for each slot in the hash. |
|
2055
|
|
|
|
|
|
|
|
|
2056
|
|
|
|
|
|
|
dokimi :t(Dict[onoma => Str, id => Optional[Int], epiloges => Dict[onama => Str]]) |
|
2057
|
|
|
|
|
|
|
|
|
2058
|
|
|
|
|
|
|
=cut |
|
2059
|
|
|
|
|
|
|
|
|
2060
|
|
|
|
|
|
|
=head3 Optional |
|
2061
|
|
|
|
|
|
|
|
|
2062
|
|
|
|
|
|
|
Used in conjunction with Dict and Tuple to specify slots that are optional and may be omitted. |
|
2063
|
|
|
|
|
|
|
|
|
2064
|
|
|
|
|
|
|
dokimi :t(Optional[Str]) |
|
2065
|
|
|
|
|
|
|
|
|
2066
|
|
|
|
|
|
|
=cut |
|
2067
|
|
|
|
|
|
|
|
|
2068
|
|
|
|
|
|
|
=head2 Macros |
|
2069
|
|
|
|
|
|
|
|
|
2070
|
|
|
|
|
|
|
Hades has a concept of macros that allow you to write re-usable code. see L<https://metacpan.org/source/LNATION/Hades-0.20/macro-fh.hades> for an example of how to extend via macros. |
|
2071
|
|
|
|
|
|
|
|
|
2072
|
|
|
|
|
|
|
macro { |
|
2073
|
|
|
|
|
|
|
FH [ macro => [qw/read_file write_file/], alias => { read_file => [qw/rf/], write_file => [qw/wf/] } ] |
|
2074
|
|
|
|
|
|
|
str2ArrayRef :a(s2ar) { |
|
2075
|
|
|
|
|
|
|
return qq|$params[0] = [ $params[0] ];|; |
|
2076
|
|
|
|
|
|
|
} |
|
2077
|
|
|
|
|
|
|
ArrayRef2Str :a(ar2s) { |
|
2078
|
|
|
|
|
|
|
return qq|$params[0] = $params[0]\->[0];|; |
|
2079
|
|
|
|
|
|
|
} |
|
2080
|
|
|
|
|
|
|
} |
|
2081
|
|
|
|
|
|
|
MacroKosmos { |
|
2082
|
|
|
|
|
|
|
eros $eros :t(Str) :d(t/test.txt) { |
|
2083
|
|
|
|
|
|
|
€s2ar('$eros'); |
|
2084
|
|
|
|
|
|
|
€ar2s('$eros'); |
|
2085
|
|
|
|
|
|
|
€wf('$eros', q|'this is a test'|); |
|
2086
|
|
|
|
|
|
|
return $eros; |
|
2087
|
|
|
|
|
|
|
} |
|
2088
|
|
|
|
|
|
|
psyche $psyche :t(Str) :d(t/test.txt) { |
|
2089
|
|
|
|
|
|
|
€rf('$psyche'); |
|
2090
|
|
|
|
|
|
|
return $content; |
|
2091
|
|
|
|
|
|
|
} |
|
2092
|
|
|
|
|
|
|
} |
|
2093
|
|
|
|
|
|
|
|
|
2094
|
|
|
|
|
|
|
... generates ... |
|
2095
|
|
|
|
|
|
|
|
|
2096
|
|
|
|
|
|
|
package MacroKosmos; |
|
2097
|
|
|
|
|
|
|
use strict; |
|
2098
|
|
|
|
|
|
|
use warnings; |
|
2099
|
|
|
|
|
|
|
our $VERSION = 0.01; |
|
2100
|
|
|
|
|
|
|
|
|
2101
|
|
|
|
|
|
|
sub new { |
|
2102
|
|
|
|
|
|
|
my ( $cls, %args ) = ( shift(), scalar @_ == 1 ? %{ $_[0] } : @_ ); |
|
2103
|
|
|
|
|
|
|
my $self = bless {}, $cls; |
|
2104
|
|
|
|
|
|
|
my %accessors = (); |
|
2105
|
|
|
|
|
|
|
for my $accessor ( keys %accessors ) { |
|
2106
|
|
|
|
|
|
|
my $value |
|
2107
|
|
|
|
|
|
|
= $self->$accessor( |
|
2108
|
|
|
|
|
|
|
defined $args{$accessor} |
|
2109
|
|
|
|
|
|
|
? $args{$accessor} |
|
2110
|
|
|
|
|
|
|
: $accessors{$accessor}->{default} ); |
|
2111
|
|
|
|
|
|
|
unless ( !$accessors{$accessor}->{required} || defined $value ) { |
|
2112
|
|
|
|
|
|
|
die "$accessor accessor is required"; |
|
2113
|
|
|
|
|
|
|
} |
|
2114
|
|
|
|
|
|
|
} |
|
2115
|
|
|
|
|
|
|
return $self; |
|
2116
|
|
|
|
|
|
|
} |
|
2117
|
|
|
|
|
|
|
|
|
2118
|
|
|
|
|
|
|
sub eros { |
|
2119
|
|
|
|
|
|
|
my ( $self, $eros ) = @_; |
|
2120
|
|
|
|
|
|
|
$eros = defined $eros ? $eros : "t/test.txt"; |
|
2121
|
|
|
|
|
|
|
if ( !defined($eros) || ref $eros ) { |
|
2122
|
|
|
|
|
|
|
$eros = defined $eros ? $eros : 'undef'; |
|
2123
|
|
|
|
|
|
|
die qq{Str: invalid value $eros for variable \$eros in method eros}; |
|
2124
|
|
|
|
|
|
|
} |
|
2125
|
|
|
|
|
|
|
|
|
2126
|
|
|
|
|
|
|
$eros = [$eros]; |
|
2127
|
|
|
|
|
|
|
$eros = $eros->[0]; |
|
2128
|
|
|
|
|
|
|
open my $wh, ">", $eros or die "cannot open file for writing: $!"; |
|
2129
|
|
|
|
|
|
|
print $wh 'this is a test'; |
|
2130
|
|
|
|
|
|
|
close $wh; |
|
2131
|
|
|
|
|
|
|
return $eros; |
|
2132
|
|
|
|
|
|
|
|
|
2133
|
|
|
|
|
|
|
} |
|
2134
|
|
|
|
|
|
|
|
|
2135
|
|
|
|
|
|
|
sub psyche { |
|
2136
|
|
|
|
|
|
|
my ( $self, $psyche ) = @_; |
|
2137
|
|
|
|
|
|
|
$psyche = defined $psyche ? $psyche : "t/test.txt"; |
|
2138
|
|
|
|
|
|
|
if ( !defined($psyche) || ref $psyche ) { |
|
2139
|
|
|
|
|
|
|
$psyche = defined $psyche ? $psyche : 'undef'; |
|
2140
|
|
|
|
|
|
|
die |
|
2141
|
|
|
|
|
|
|
qq{Str: invalid value $psyche for variable \$psyche in method psyche}; |
|
2142
|
|
|
|
|
|
|
} |
|
2143
|
|
|
|
|
|
|
|
|
2144
|
|
|
|
|
|
|
open my $fh, "<", $psyche or die "cannot open file for reading: $!"; |
|
2145
|
|
|
|
|
|
|
my $content = do { local $/; <$fh> }; |
|
2146
|
|
|
|
|
|
|
close $fh; |
|
2147
|
|
|
|
|
|
|
return $content; |
|
2148
|
|
|
|
|
|
|
} |
|
2149
|
|
|
|
|
|
|
|
|
2150
|
|
|
|
|
|
|
1; |
|
2151
|
|
|
|
|
|
|
|
|
2152
|
|
|
|
|
|
|
__END__ |
|
2153
|
|
|
|
|
|
|
|
|
2154
|
|
|
|
|
|
|
=head2 Testing |
|
2155
|
|
|
|
|
|
|
|
|
2156
|
|
|
|
|
|
|
Hades can auto-generate test files. If you take the following example: |
|
2157
|
|
|
|
|
|
|
|
|
2158
|
|
|
|
|
|
|
use Hades; |
|
2159
|
|
|
|
|
|
|
Hades->run({ |
|
2160
|
|
|
|
|
|
|
eval => q|Dokimes { |
|
2161
|
|
|
|
|
|
|
curae :r :default(5) |
|
2162
|
|
|
|
|
|
|
penthos :t(Str) :r |
|
2163
|
|
|
|
|
|
|
nosoi :default(3) :t(Int) :clearer |
|
2164
|
|
|
|
|
|
|
limos |
|
2165
|
|
|
|
|
|
|
$test :t(Str) |
|
2166
|
|
|
|
|
|
|
:test( |
|
2167
|
|
|
|
|
|
|
['ok', '$obj->penthos(2) && $obj->nosoi(2) && $obj->curae(5)'], |
|
2168
|
|
|
|
|
|
|
['is', '$obj->limos("yay")', 5 ], |
|
2169
|
|
|
|
|
|
|
['ok', '$obj->penthos(5)' ], |
|
2170
|
|
|
|
|
|
|
['is', '$obj->limos("yay")', q{''}] |
|
2171
|
|
|
|
|
|
|
) |
|
2172
|
|
|
|
|
|
|
{ if ($_[0]->penthos == $_[0]->nosoi) { return $_[0]->curae; } } |
|
2173
|
|
|
|
|
|
|
}|, |
|
2174
|
|
|
|
|
|
|
lib => 'lib', |
|
2175
|
|
|
|
|
|
|
tlib => 't/lib', |
|
2176
|
|
|
|
|
|
|
}); |
|
2177
|
|
|
|
|
|
|
|
|
2178
|
|
|
|
|
|
|
|
|
2179
|
|
|
|
|
|
|
It will generate a test file located at t/lib/Dokimes.t which looks like: |
|
2180
|
|
|
|
|
|
|
|
|
2181
|
|
|
|
|
|
|
use Test::More; |
|
2182
|
|
|
|
|
|
|
use strict; |
|
2183
|
|
|
|
|
|
|
use warnings; |
|
2184
|
|
|
|
|
|
|
BEGIN { use_ok('Dokimes'); } |
|
2185
|
|
|
|
|
|
|
subtest 'new' => sub { |
|
2186
|
|
|
|
|
|
|
plan tests => 16; |
|
2187
|
|
|
|
|
|
|
ok( my $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ), |
|
2188
|
|
|
|
|
|
|
q{my $obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})} |
|
2189
|
|
|
|
|
|
|
); |
|
2190
|
|
|
|
|
|
|
ok( $obj = Dokimes->new( curae => 'hypnos', penthos => 'aporia' ), |
|
2191
|
|
|
|
|
|
|
q{$obj = Dokimes->new(curae => 'hypnos', penthos => 'aporia')} |
|
2192
|
|
|
|
|
|
|
); |
|
2193
|
|
|
|
|
|
|
isa_ok( $obj, 'Dokimes' ); |
|
2194
|
|
|
|
|
|
|
ok( $obj = Dokimes->new( { penthos => 'aporia', nosoi => 10 } ), |
|
2195
|
|
|
|
|
|
|
q{$obj = Dokimes->new({penthos => 'aporia', nosoi => 10})} |
|
2196
|
|
|
|
|
|
|
); |
|
2197
|
|
|
|
|
|
|
ok( $obj = Dokimes->new( penthos => 'aporia', nosoi => 10 ), |
|
2198
|
|
|
|
|
|
|
q{$obj = Dokimes->new(penthos => 'aporia', nosoi => 10)} |
|
2199
|
|
|
|
|
|
|
); |
|
2200
|
|
|
|
|
|
|
is( $obj->curae, 5, q{$obj->curae} ); |
|
2201
|
|
|
|
|
|
|
ok( $obj = Dokimes->new( |
|
2202
|
|
|
|
|
|
|
{ curae => 'hypnos', penthos => 'aporia', nosoi => 10 } |
|
2203
|
|
|
|
|
|
|
), |
|
2204
|
|
|
|
|
|
|
q{$obj = Dokimes->new({ curae => 'hypnos', penthos => 'aporia', nosoi => 10 })} |
|
2205
|
|
|
|
|
|
|
); |
|
2206
|
|
|
|
|
|
|
eval { $obj = Dokimes->new( { curae => 'hypnos', nosoi => 10 } ) }; |
|
2207
|
|
|
|
|
|
|
like( $@, qr/required/, |
|
2208
|
|
|
|
|
|
|
q{$obj = Dokimes->new({curae => 'hypnos', nosoi => 10})} ); |
|
2209
|
|
|
|
|
|
|
eval { |
|
2210
|
|
|
|
|
|
|
$obj = Dokimes->new( |
|
2211
|
|
|
|
|
|
|
{ curae => 'hypnos', penthos => [], nosoi => 10 } ); |
|
2212
|
|
|
|
|
|
|
}; |
|
2213
|
|
|
|
|
|
|
like( |
|
2214
|
|
|
|
|
|
|
$@, |
|
2215
|
|
|
|
|
|
|
qr/invalid value|greater|atleast/, |
|
2216
|
|
|
|
|
|
|
q{$obj = Dokimes->new({ curae => 'hypnos', penthos => [], nosoi => 10 })} |
|
2217
|
|
|
|
|
|
|
); |
|
2218
|
|
|
|
|
|
|
eval { |
|
2219
|
|
|
|
|
|
|
$obj = Dokimes->new( |
|
2220
|
|
|
|
|
|
|
{ curae => 'hypnos', penthos => \1, nosoi => 10 } ); |
|
2221
|
|
|
|
|
|
|
}; |
|
2222
|
|
|
|
|
|
|
like( |
|
2223
|
|
|
|
|
|
|
$@, |
|
2224
|
|
|
|
|
|
|
qr/invalid value|greater|atleast/, |
|
2225
|
|
|
|
|
|
|
q{$obj = Dokimes->new({ curae => 'hypnos', penthos => \1, nosoi => 10 })} |
|
2226
|
|
|
|
|
|
|
); |
|
2227
|
|
|
|
|
|
|
eval { |
|
2228
|
|
|
|
|
|
|
$obj = Dokimes->new( |
|
2229
|
|
|
|
|
|
|
{ curae => 'hypnos', penthos => '', nosoi => 10 } ); |
|
2230
|
|
|
|
|
|
|
}; |
|
2231
|
|
|
|
|
|
|
like( |
|
2232
|
|
|
|
|
|
|
$@, |
|
2233
|
|
|
|
|
|
|
qr/invalid value|greater|atleast/, |
|
2234
|
|
|
|
|
|
|
q{$obj = Dokimes->new({ curae => 'hypnos', penthos => '', nosoi => 10 })} |
|
2235
|
|
|
|
|
|
|
); |
|
2236
|
|
|
|
|
|
|
ok( $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ), |
|
2237
|
|
|
|
|
|
|
q{$obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})} |
|
2238
|
|
|
|
|
|
|
); |
|
2239
|
|
|
|
|
|
|
ok( $obj = Dokimes->new( curae => 'hypnos', penthos => 'aporia' ), |
|
2240
|
|
|
|
|
|
|
q{$obj = Dokimes->new(curae => 'hypnos', penthos => 'aporia')} |
|
2241
|
|
|
|
|
|
|
); |
|
2242
|
|
|
|
|
|
|
is( $obj->nosoi, 3, q{$obj->nosoi} ); |
|
2243
|
|
|
|
|
|
|
eval { |
|
2244
|
|
|
|
|
|
|
$obj = Dokimes->new( |
|
2245
|
|
|
|
|
|
|
{ curae => 'hypnos', penthos => 'aporia', nosoi => [] } ); |
|
2246
|
|
|
|
|
|
|
}; |
|
2247
|
|
|
|
|
|
|
like( |
|
2248
|
|
|
|
|
|
|
$@, |
|
2249
|
|
|
|
|
|
|
qr/invalid value|greater|atleast/, |
|
2250
|
|
|
|
|
|
|
q{$obj = Dokimes->new({ curae => 'hypnos', penthos => 'aporia', nosoi => [] })} |
|
2251
|
|
|
|
|
|
|
); |
|
2252
|
|
|
|
|
|
|
eval { |
|
2253
|
|
|
|
|
|
|
$obj = Dokimes->new( |
|
2254
|
|
|
|
|
|
|
{ curae => 'hypnos', penthos => 'aporia', nosoi => 'limos' } ); |
|
2255
|
|
|
|
|
|
|
}; |
|
2256
|
|
|
|
|
|
|
like( |
|
2257
|
|
|
|
|
|
|
$@, |
|
2258
|
|
|
|
|
|
|
qr/invalid value|greater|atleast/, |
|
2259
|
|
|
|
|
|
|
q{$obj = Dokimes->new({ curae => 'hypnos', penthos => 'aporia', nosoi => 'limos' })} |
|
2260
|
|
|
|
|
|
|
); |
|
2261
|
|
|
|
|
|
|
}; |
|
2262
|
|
|
|
|
|
|
subtest 'curae' => sub { |
|
2263
|
|
|
|
|
|
|
plan tests => 2; |
|
2264
|
|
|
|
|
|
|
ok( my $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ), |
|
2265
|
|
|
|
|
|
|
q{my $obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})} |
|
2266
|
|
|
|
|
|
|
); |
|
2267
|
|
|
|
|
|
|
can_ok( $obj, 'curae' ); |
|
2268
|
|
|
|
|
|
|
}; |
|
2269
|
|
|
|
|
|
|
subtest 'penthos' => sub { |
|
2270
|
|
|
|
|
|
|
plan tests => 7; |
|
2271
|
|
|
|
|
|
|
ok( my $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ), |
|
2272
|
|
|
|
|
|
|
q{my $obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})} |
|
2273
|
|
|
|
|
|
|
); |
|
2274
|
|
|
|
|
|
|
can_ok( $obj, 'penthos' ); |
|
2275
|
|
|
|
|
|
|
is_deeply( $obj->penthos('curae'), 'curae', q{$obj->penthos('curae')} ); |
|
2276
|
|
|
|
|
|
|
eval { $obj->penthos( [] ) }; |
|
2277
|
|
|
|
|
|
|
like( $@, qr/invalid value|greater|atleast/, q{$obj->penthos([])} ); |
|
2278
|
|
|
|
|
|
|
eval { $obj->penthos( \1 ) }; |
|
2279
|
|
|
|
|
|
|
like( $@, qr/invalid value|greater|atleast/, q{$obj->penthos(\1)} ); |
|
2280
|
|
|
|
|
|
|
eval { $obj->penthos('') }; |
|
2281
|
|
|
|
|
|
|
like( $@, qr/invalid value|greater|atleast/, q{$obj->penthos('')} ); |
|
2282
|
|
|
|
|
|
|
is_deeply( $obj->penthos, 'curae', q{$obj->penthos} ); |
|
2283
|
|
|
|
|
|
|
}; |
|
2284
|
|
|
|
|
|
|
subtest 'nosoi' => sub { |
|
2285
|
|
|
|
|
|
|
plan tests => 6; |
|
2286
|
|
|
|
|
|
|
ok( my $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ), |
|
2287
|
|
|
|
|
|
|
q{my $obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})} |
|
2288
|
|
|
|
|
|
|
); |
|
2289
|
|
|
|
|
|
|
can_ok( $obj, 'nosoi' ); |
|
2290
|
|
|
|
|
|
|
is_deeply( $obj->nosoi(10), 10, q{$obj->nosoi(10)} ); |
|
2291
|
|
|
|
|
|
|
eval { $obj->nosoi( [] ) }; |
|
2292
|
|
|
|
|
|
|
like( $@, qr/invalid value|greater|atleast/, q{$obj->nosoi([])} ); |
|
2293
|
|
|
|
|
|
|
eval { $obj->nosoi('phobos') }; |
|
2294
|
|
|
|
|
|
|
like( $@, qr/invalid value|greater|atleast/, q{$obj->nosoi('phobos')} ); |
|
2295
|
|
|
|
|
|
|
is_deeply( $obj->nosoi, 10, q{$obj->nosoi} ); |
|
2296
|
|
|
|
|
|
|
}; |
|
2297
|
|
|
|
|
|
|
subtest 'limos' => sub { |
|
2298
|
|
|
|
|
|
|
plan tests => 10; |
|
2299
|
|
|
|
|
|
|
ok( my $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ), |
|
2300
|
|
|
|
|
|
|
q{my $obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})} |
|
2301
|
|
|
|
|
|
|
); |
|
2302
|
|
|
|
|
|
|
can_ok( $obj, 'limos' ); |
|
2303
|
|
|
|
|
|
|
eval { $obj->limos( [] ) }; |
|
2304
|
|
|
|
|
|
|
like( $@, qr/invalid value|greater|atleast/, q{$obj->limos([])} ); |
|
2305
|
|
|
|
|
|
|
eval { $obj->limos( \1 ) }; |
|
2306
|
|
|
|
|
|
|
like( $@, qr/invalid value|greater|atleast/, q{$obj->limos(\1)} ); |
|
2307
|
|
|
|
|
|
|
eval { $obj->limos('') }; |
|
2308
|
|
|
|
|
|
|
like( $@, qr/invalid value|greater|atleast/, q{$obj->limos('')} ); |
|
2309
|
|
|
|
|
|
|
eval { $obj->limos(undef) }; |
|
2310
|
|
|
|
|
|
|
like( $@, qr/invalid value|greater|atleast/, q{$obj->limos(undef)} ); |
|
2311
|
|
|
|
|
|
|
ok( $obj->penthos(2) && $obj->nosoi(2) && $obj->curae(5), |
|
2312
|
|
|
|
|
|
|
q{$obj->penthos(2) && $obj->nosoi(2) && $obj->curae(5)} |
|
2313
|
|
|
|
|
|
|
); |
|
2314
|
|
|
|
|
|
|
is( $obj->limos("yay"), 5, q{$obj->limos("yay")} ); |
|
2315
|
|
|
|
|
|
|
ok( $obj->penthos(5), q{$obj->penthos(5)} ); |
|
2316
|
|
|
|
|
|
|
is( $obj->limos("yay"), '', q{$obj->limos("yay")} ); |
|
2317
|
|
|
|
|
|
|
}; |
|
2318
|
|
|
|
|
|
|
subtest 'clear_nosoi' => sub { |
|
2319
|
|
|
|
|
|
|
plan tests => 5; |
|
2320
|
|
|
|
|
|
|
ok( my $obj = Dokimes->new( { curae => 'hypnos', penthos => 'aporia' } ), |
|
2321
|
|
|
|
|
|
|
q{my $obj = Dokimes->new({curae => 'hypnos', penthos => 'aporia'})} |
|
2322
|
|
|
|
|
|
|
); |
|
2323
|
|
|
|
|
|
|
can_ok( $obj, 'clear_nosoi' ); |
|
2324
|
|
|
|
|
|
|
is_deeply( $obj->nosoi(10), 10, q{$obj->nosoi(10)} ); |
|
2325
|
|
|
|
|
|
|
ok( $obj->clear_nosoi, q{$obj->clear_nosoi} ); |
|
2326
|
|
|
|
|
|
|
is( $obj->nosoi, undef, q{$obj->nosoi} ); |
|
2327
|
|
|
|
|
|
|
}; |
|
2328
|
|
|
|
|
|
|
done_testing(); |
|
2329
|
|
|
|
|
|
|
|
|
2330
|
|
|
|
|
|
|
|
|
2331
|
|
|
|
|
|
|
and has 100% test coverage. |
|
2332
|
|
|
|
|
|
|
|
|
2333
|
|
|
|
|
|
|
cover --test |
|
2334
|
|
|
|
|
|
|
|
|
2335
|
|
|
|
|
|
|
------------------- ------ ------ ------ ------ ------ ------ |
|
2336
|
|
|
|
|
|
|
File stmt bran cond sub time total |
|
2337
|
|
|
|
|
|
|
------------------- ------ ------ ------ ------ ------ ------ |
|
2338
|
|
|
|
|
|
|
blib/lib/Dokimes.pm 100.0 100.0 100.0 100.0 100.0 100.0 |
|
2339
|
|
|
|
|
|
|
Total 100.0 100.0 100.0 100.0 100.0 100.0 |
|
2340
|
|
|
|
|
|
|
------------------- ------ ------ ------ ------ ------ ------ |
|
2341
|
|
|
|
|
|
|
|
|
2342
|
|
|
|
|
|
|
=cut |
|
2343
|
|
|
|
|
|
|
|
|
2344
|
|
|
|
|
|
|
=head3 tests |
|
2345
|
|
|
|
|
|
|
|
|
2346
|
|
|
|
|
|
|
Unfortunately not all code can have auto generated tests, so you should use the :test attribute to define additional |
|
2347
|
|
|
|
|
|
|
to test custom logic. |
|
2348
|
|
|
|
|
|
|
|
|
2349
|
|
|
|
|
|
|
=cut |
|
2350
|
|
|
|
|
|
|
|
|
2351
|
|
|
|
|
|
|
=head4 ok |
|
2352
|
|
|
|
|
|
|
|
|
2353
|
|
|
|
|
|
|
This simply evaluates any expression ($got eq $expected is just a simple example) and uses that to determine if the test succeeded or failed. A true expression passes, a false one fails. |
|
2354
|
|
|
|
|
|
|
|
|
2355
|
|
|
|
|
|
|
['ok', '$obj->$method'] |
|
2356
|
|
|
|
|
|
|
|
|
2357
|
|
|
|
|
|
|
=cut |
|
2358
|
|
|
|
|
|
|
|
|
2359
|
|
|
|
|
|
|
=head4 can_ok |
|
2360
|
|
|
|
|
|
|
|
|
2361
|
|
|
|
|
|
|
Checks to make sure the $module or $object can do these @methods (works with functions, too). |
|
2362
|
|
|
|
|
|
|
|
|
2363
|
|
|
|
|
|
|
['can_ok', '$obj', $method] |
|
2364
|
|
|
|
|
|
|
|
|
2365
|
|
|
|
|
|
|
=cut |
|
2366
|
|
|
|
|
|
|
|
|
2367
|
|
|
|
|
|
|
=head4 isa_ok |
|
2368
|
|
|
|
|
|
|
|
|
2369
|
|
|
|
|
|
|
Checks to see if the given $object->isa($class). Also checks to make sure the object was defined in the first place. Handy for this sort of thing: |
|
2370
|
|
|
|
|
|
|
|
|
2371
|
|
|
|
|
|
|
['isa_ok', '$obj', $class] |
|
2372
|
|
|
|
|
|
|
|
|
2373
|
|
|
|
|
|
|
=cut |
|
2374
|
|
|
|
|
|
|
|
|
2375
|
|
|
|
|
|
|
=head4 is |
|
2376
|
|
|
|
|
|
|
|
|
2377
|
|
|
|
|
|
|
Similar to ok(), is() and isnt() compare their two arguments with eq and ne respectively and use the result of that to determine if the test succeeded or failed. So these: |
|
2378
|
|
|
|
|
|
|
|
|
2379
|
|
|
|
|
|
|
['is', '$obj->$method', $expected] |
|
2380
|
|
|
|
|
|
|
|
|
2381
|
|
|
|
|
|
|
=cut |
|
2382
|
|
|
|
|
|
|
|
|
2383
|
|
|
|
|
|
|
=head4 isnt |
|
2384
|
|
|
|
|
|
|
|
|
2385
|
|
|
|
|
|
|
['isnt', '$obj->$method', $expected] |
|
2386
|
|
|
|
|
|
|
|
|
2387
|
|
|
|
|
|
|
=cut |
|
2388
|
|
|
|
|
|
|
|
|
2389
|
|
|
|
|
|
|
=head4 like |
|
2390
|
|
|
|
|
|
|
|
|
2391
|
|
|
|
|
|
|
Similar to ok(), like() matches $got against the regex qr/expected/. |
|
2392
|
|
|
|
|
|
|
|
|
2393
|
|
|
|
|
|
|
['like', '$obj->$method', $expected_regex] |
|
2394
|
|
|
|
|
|
|
|
|
2395
|
|
|
|
|
|
|
=cut |
|
2396
|
|
|
|
|
|
|
|
|
2397
|
|
|
|
|
|
|
=head4 unlike |
|
2398
|
|
|
|
|
|
|
|
|
2399
|
|
|
|
|
|
|
Works exactly as like(), only it checks if $got does not match the given pattern. |
|
2400
|
|
|
|
|
|
|
|
|
2401
|
|
|
|
|
|
|
['unlike', '$obj->$method', $expected_regex] |
|
2402
|
|
|
|
|
|
|
|
|
2403
|
|
|
|
|
|
|
=cut |
|
2404
|
|
|
|
|
|
|
|
|
2405
|
|
|
|
|
|
|
=head4 deep |
|
2406
|
|
|
|
|
|
|
|
|
2407
|
|
|
|
|
|
|
Similar to is(), except that if $got and $expected are references, it does a deep comparison walking each data structure to see if they are equivalent. If the two structures are different, it will display the place where they start differing. |
|
2408
|
|
|
|
|
|
|
|
|
2409
|
|
|
|
|
|
|
['deep', '$obj->$method', $expected] |
|
2410
|
|
|
|
|
|
|
|
|
2411
|
|
|
|
|
|
|
=cut |
|
2412
|
|
|
|
|
|
|
|
|
2413
|
|
|
|
|
|
|
=head4 eval |
|
2414
|
|
|
|
|
|
|
|
|
2415
|
|
|
|
|
|
|
Evaluate code that you expect to die and check the warning using like. |
|
2416
|
|
|
|
|
|
|
|
|
2417
|
|
|
|
|
|
|
['eval', '$obj->$method", $error_expected] |
|
2418
|
|
|
|
|
|
|
|
|
2419
|
|
|
|
|
|
|
=cut |
|
2420
|
|
|
|
|
|
|
|
|
2421
|
|
|
|
|
|
|
=head1 AUTHOR |
|
2422
|
|
|
|
|
|
|
|
|
2423
|
|
|
|
|
|
|
LNATION, C<< <email at lnation.org> >> |
|
2424
|
|
|
|
|
|
|
|
|
2425
|
|
|
|
|
|
|
=head1 BUGS |
|
2426
|
|
|
|
|
|
|
|
|
2427
|
|
|
|
|
|
|
Please report any bugs or feature requests to C<bug-hades at rt.cpan.org>, or through |
|
2428
|
|
|
|
|
|
|
the web interface at L<https://rt.cpan.org/NoAuth/ReportBug.html?Queue=Hades>. I will be notified, and then you'll |
|
2429
|
|
|
|
|
|
|
automatically be notified of progress on your bug as I make changes. |
|
2430
|
|
|
|
|
|
|
|
|
2431
|
|
|
|
|
|
|
=head1 SUPPORT |
|
2432
|
|
|
|
|
|
|
|
|
2433
|
|
|
|
|
|
|
You can find documentation for this module with the perldoc command. |
|
2434
|
|
|
|
|
|
|
|
|
2435
|
|
|
|
|
|
|
perldoc Hades |
|
2436
|
|
|
|
|
|
|
|
|
2437
|
|
|
|
|
|
|
You can also look for information at: |
|
2438
|
|
|
|
|
|
|
|
|
2439
|
|
|
|
|
|
|
=over 4 |
|
2440
|
|
|
|
|
|
|
|
|
2441
|
|
|
|
|
|
|
=item * RT: CPAN's request tracker (report bugs here) |
|
2442
|
|
|
|
|
|
|
|
|
2443
|
|
|
|
|
|
|
L<https://rt.cpan.org/NoAuth/Bugs.html?Dist=Hades> |
|
2444
|
|
|
|
|
|
|
|
|
2445
|
|
|
|
|
|
|
=item * AnnoCPAN: Annotated CPAN documentation |
|
2446
|
|
|
|
|
|
|
|
|
2447
|
|
|
|
|
|
|
L<http://annocpan.org/dist/Hades> |
|
2448
|
|
|
|
|
|
|
|
|
2449
|
|
|
|
|
|
|
=item * CPAN Ratings |
|
2450
|
|
|
|
|
|
|
|
|
2451
|
|
|
|
|
|
|
L<https://cpanratings.perl.org/d/Hades> |
|
2452
|
|
|
|
|
|
|
|
|
2453
|
|
|
|
|
|
|
=item * Search CPAN |
|
2454
|
|
|
|
|
|
|
|
|
2455
|
|
|
|
|
|
|
L<https://metacpan.org/release/Hades> |
|
2456
|
|
|
|
|
|
|
|
|
2457
|
|
|
|
|
|
|
=back |
|
2458
|
|
|
|
|
|
|
|
|
2459
|
|
|
|
|
|
|
|
|
2460
|
|
|
|
|
|
|
=head1 ACKNOWLEDGEMENTS |
|
2461
|
|
|
|
|
|
|
|
|
2462
|
|
|
|
|
|
|
|
|
2463
|
|
|
|
|
|
|
=head1 LICENSE AND COPYRIGHT |
|
2464
|
|
|
|
|
|
|
|
|
2465
|
|
|
|
|
|
|
This software is Copyright (c) 2020 by LNATION. |
|
2466
|
|
|
|
|
|
|
|
|
2467
|
|
|
|
|
|
|
This is free software, licensed under: |
|
2468
|
|
|
|
|
|
|
|
|
2469
|
|
|
|
|
|
|
The Artistic License 2.0 (GPL Compatible) |
|
2470
|
|
|
|
|
|
|
|
|
2471
|
|
|
|
|
|
|
|
|
2472
|
|
|
|
|
|
|
=cut |
|
2473
|
|
|
|
|
|
|
|
|
2474
|
|
|
|
|
|
|
1; # End of Hades |