File Coverage

blib/lib/Hades.pm
Criterion Covered Total %
statement 653 721 90.5
branch 206 268 76.8
condition 75 98 76.5
subroutine 93 119 78.1
pod 3 44 6.8
total 1030 1250 82.4


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