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