File Coverage

blib/lib/Hades.pm
Criterion Covered Total %
statement 653 721 90.5
branch 210 272 77.2
condition 75 98 76.5
subroutine 93 119 78.1
pod 3 44 6.8
total 1034 1254 82.4


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