File Coverage

blib/lib/AI/Evolve/Befunge/Util.pm
Criterion Covered Total %
statement 188 188 100.0
branch 62 62 100.0
condition 9 9 100.0
subroutine 44 44 100.0
pod 18 18 100.0
total 321 321 100.0


line stmt bran cond sub pod time code
1             package AI::Evolve::Befunge::Util;
2 8     8   357595 use strict;
  8         6309  
  8         399  
3 8     8   46 use warnings;
  8         14  
  8         243  
4              
5 8     8   47 use Carp;
  8         17  
  8         667  
6 8     8   7991 use IO::Socket;
  8         218925  
  8         37  
7 8     8   11472 use Language::Befunge::Vector;
  8         36679  
  8         284  
8 8     8   4631 use Perl6::Export::Attrs;
  8         65651  
  8         75  
9 8     8   568 use Socket qw(AF_UNIX SOCK_STREAM PF_UNSPEC);
  8         19  
  8         2819  
10 8     8   7857 use YAML qw(LoadFile Load Dump);
  8         82724  
  8         803  
11              
12 8     8   5334 use aliased 'AI::Evolve::Befunge::Util::Config' => 'Config';
  8         4860  
  8         66  
13              
14             $ENV{HOST} = global_config("hostname", `hostname`);
15             $ENV{HOST} = "unknown-host-$$-" . int rand 65536 unless defined $ENV{HOST};
16             chomp $ENV{HOST};
17              
18             my @quiet = 0;
19             my @verbose = 0;
20             my @debug = 0;
21              
22              
23             =head1 NAME
24              
25             AI::Evolve::Befunge::Util - common utility functions
26              
27              
28             =head1 DESCRIPTION
29              
30             This is a place for miscellaneous stuff that is used elsewhere
31             throughout the AI::Evolve::Befunge codespace.
32              
33              
34             =head1 FUNCTIONS
35              
36             =head2 push_quiet
37              
38             push_quiet(1);
39              
40             Add a new value to the "quiet" stack.
41              
42             =cut
43              
44             sub push_quiet :Export(:DEFAULT) {
45 3     3 1 462 my $new = shift;
46 3         11 push(@quiet, $new);
47 8     8   1927 }
  8         17  
  8         76  
48              
49              
50             =head2 pop_quiet
51              
52             pop_quiet();
53              
54             Remove the topmost entry from the "quiet" stack, if more than one
55             item exists on the stack.
56              
57             =cut
58              
59             sub pop_quiet :Export(:DEFAULT) {
60 3     3 1 1345 my $new = shift;
61 3 100       16 pop(@quiet) if @quiet > 1;
62 8     8   4001 }
  8         15  
  8         41  
63              
64              
65             =head2 get_quiet
66              
67             $quiet = get_quiet();
68              
69             Returns the topmost entry on the "quiet" stack.
70              
71             =cut
72              
73             sub get_quiet :Export(:DEFAULT) {
74 9     9 1 68 return $quiet[-1];
75 8     8   2400 }
  8         18  
  8         34  
76              
77              
78             =head2 push_verbose
79              
80             push_verbose(1);
81              
82             Add a new value to the "verbose" stack.
83              
84             =cut
85              
86             sub push_verbose :Export(:DEFAULT) {
87 1     1 1 3 my $new = shift;
88 1         3 push(@verbose, $new);
89 8     8   2007 }
  8         15  
  8         33  
90              
91              
92             =head2 pop_verbose
93              
94             pop_verbose();
95              
96             Remove the topmost entry from the "verbose" stack, if more than one
97             item exists on the stack.
98              
99             =cut
100              
101             sub pop_verbose :Export(:DEFAULT) {
102 2     2 1 4 my $new = shift;
103 2 100       10 pop(@verbose) if @verbose > 1;
104 8     8   1996 }
  8         23  
  8         46  
105              
106              
107             =head2 get_verbose
108              
109             $quiet = get_verbose();
110              
111             Returns the topmost entry on the "verbose" stack.
112              
113             =cut
114              
115             sub get_verbose :Export(:DEFAULT) {
116 3     3 1 21 return $verbose[-1];
117 8     8   2260 }
  8         15  
  8         41  
118              
119              
120             =head2 push_debug
121              
122             push_debug(1);
123              
124             Add a new value to the "debug" stack.
125              
126             =cut
127              
128             sub push_debug :Export(:DEFAULT) {
129 2     2 1 731 my $new = shift;
130 2         7 push(@debug, $new);
131 8     8   2341 }
  8         14  
  8         51  
132              
133              
134             =head2 pop_debug
135              
136             pop_debug();
137              
138             Remove the topmost entry from the "debug" stack, if more than one
139             item exists on the stack.
140              
141             =cut
142              
143             sub pop_debug :Export(:DEFAULT) {
144 3     3 1 1172 my $new = shift;
145 3 100       30 pop(@debug) if @debug > 1;
146 8     8   2047 }
  8         21  
  8         38  
147              
148              
149             =head2 get_debug
150              
151             $quiet = get_debug();
152              
153             Returns the topmost entry on the "debug" stack.
154              
155             =cut
156              
157             sub get_debug :Export(:DEFAULT) {
158 3     3 1 15 return $debug[-1];
159 8     8   2319 }
  8         39  
  8         38  
160              
161              
162             =head2 verbose
163              
164             verbose("Hi! I'm in verbose mode!\n");
165              
166             Output a message if get_verbose() is true.
167              
168             =cut
169              
170             sub verbose :Export(:DEFAULT) {
171 6 100   6 1 1890 print(@_) if $verbose[-1];
172 8     8   1996 }
  8         17  
  8         32  
173              
174              
175             =head2 debug
176              
177             verbose("Hi! I'm in debug mode!\n");
178              
179             Output a message if get_debug() is true.
180              
181             =cut
182              
183             sub debug :Export(:DEFAULT) {
184 33 100   33 1 1704 print(@_) if $debug[-1];
185 8     8   2276 }
  8         23  
  8         51  
186              
187              
188             =head2 quiet
189              
190             quiet("Hi! I'm in quiet mode!\n");
191              
192             Output a message if get_quiet() is true. Note that this probably
193             isn't very useful.
194              
195             =cut
196              
197             sub quiet :Export(:DEFAULT) {
198 2 100   2 1 2372 print(@_) if $quiet[-1];
199 8     8   2526 }
  8         54  
  8         34  
200              
201              
202             =head2 nonquiet
203              
204             verbose("Hi! I'm not in quiet mode!\n");
205              
206             Output a message if get_quiet() is false.
207              
208             =cut
209              
210             sub nonquiet :Export(:DEFAULT) {
211 2 100   2 1 1476 print(@_) unless $quiet[-1];
212 8     8   2001 }
  8         20  
  8         45  
213              
214              
215             =head2 v
216              
217             my $vector = v(1,2);
218              
219             Shorthand for creating a Language::Befunge::Vector object.
220              
221             =cut
222              
223             sub v :Export(:DEFAULT) {
224 1908     1908 1 64711 return Language::Befunge::Vector->new(@_);
225 8     8   2950 }
  8         15  
  8         52  
226              
227              
228             =head2 code_print
229              
230             code_print($code, $x_size, $y_size);
231              
232             Pretty-print a chunk of code to stdout.
233              
234             =cut
235              
236             sub code_print :Export(:DEFAULT) {
237 7     7 1 1598 my ($code, $sizex, $sizey) = @_;
238 7         21 my $usage = 'Usage: code_print($code, $sizex, $sizey)';
239 7 100       48 croak($usage) unless defined $code;
240 6 100       32 croak($usage) unless defined $sizex;
241 5 100       37 croak($usage) unless defined $sizey;
242 4         9 my $charlen = 1;
243 4         7 my $hex = 0;
244 4         33 foreach my $char (split("",$code)) {
245 87 100       155 if($char ne "\n") {
246 79 100       178 if($char !~ /[[:print:]]/) {
247 25         25 $hex = 1;
248             }
249 79         179 my $len = length(sprintf("%x",ord($char))) + 1;
250 79 100       151 $charlen = $len if $charlen < $len;
251             }
252             }
253 4 100       36 $code =~ s/\n//g unless $hex;
254 4 100       16 $charlen = 1 unless $hex;
255 4         12 my $space = " " x ($charlen);
256 4 100       18 if($sizex > 9) {
257 1         33 print(" ");
258 1         5 for my $x (0..$sizex-1) {
259 11 100 100     51 unless(!$x || ($x % 10)) {
260 1         16 printf("%${charlen}i",$x / 10);
261             } else {
262 10         93 print($space);
263             }
264             }
265 1         10 print("\n");
266             }
267 4         238 print(" ");
268 4         17 for my $x (0..$sizex-1) {
269 23         245 printf("%${charlen}i",$x % 10);
270             }
271 4         87 print("\n");
272 4         14 foreach my $y (0..$sizey-1) {
273 15         177 printf("%2i ", $y);
274 15 100       39 if($hex) {
275 3         9 foreach my $x (0..$sizex-1) {
276 33         35 my $val;
277 33 100       87 $val = substr($code,$y*$sizex+$x,1)
278             if length($code) >= $y*$sizex+$x;
279 33 100       49 if(defined($val)) {
280 27         31 $val = ord($val);
281             } else {
282 6         11 $val = 0;
283             }
284 33         62 $val = sprintf("%${charlen}x",$val);
285 33         347 print($val);
286             }
287             } else {
288 12         118 print(substr($code,$y*$sizex,$sizex));
289             }
290 15         158 printf("\n");
291             }
292 8     8   6186 }
  8         24  
  8         35  
293              
294              
295             =head2 setup_configs
296              
297             setup_configs();
298              
299             Load the config files from disk, set up the various data structures
300             to allow fetching global and overrideable configs. This is called
301             internally by L and L, so you never
302             have to call it directly.
303              
304             =cut
305              
306             my $loaded_config_before = 0;
307             my @all_configs = {};
308             my $global_config;
309             sub setup_configs {
310 21 100   21 1 523 return if $loaded_config_before;
311 11         59 my %global_config;
312 11         135 my @config_files = (
313             "/etc/ai-evolve-befunge.conf",
314             $ENV{HOME}."/.ai-evolve-befunge",
315             );
316 11 100       149 push(@config_files, $ENV{AIEVOLVEBEFUNGE}) if exists $ENV{AIEVOLVEBEFUNGE};
317 11         80 foreach my $config_file (@config_files) {
318 30 100       874 next unless -r $config_file;
319 8         145 push(@all_configs, LoadFile($config_file));
320             }
321 11         388105 foreach my $config (@all_configs) {
322 11         73 my %skiplist = (byhost => 1, bygen => 1, byphysics => 1);
323 11         91 foreach my $keyword (keys %$config) {
324 116 100       396 next if exists $skiplist{$keyword};
325 104         346 $global_config{$keyword} = $$config{$keyword};
326             }
327             }
328 11         493 $global_config = Config->new({hash => \%global_config});
329 11         281 $loaded_config_before = 1;
330             }
331              
332              
333             =head2 global_config
334              
335             my $value = global_config('name');
336             my $value = global_config('name', 'default');
337             my @list = global_config('name', 'default');
338             my @list = global_config('name', ['default1', 'default2']);
339              
340             Fetch some config from the config file. This queries the global
341             config database - it will not take local overrides (for host,
342             generation, or physics plugin) into account. For more specific
343             (and flexible) config, see L, below.
344              
345             =cut
346              
347             sub global_config :Export(:DEFAULT) {
348 15     15 1 210 setup_configs();
349 15         319 return $global_config->config(@_);
350 8     8   4315 }
  8         18  
  8         35  
351              
352              
353             =head2 custom_config
354              
355             my $config = custom_config(host => $host, physics => $physics, gen => $gen);
356             my $value = $config('name');
357             my $value = $config('name', 'default');
358             my @list = $config('name', 'default');
359             my @list = $config('name', ['default1', 'default2']);
360              
361             Generate a config object from the config file. This queries the
362             global config database, but allows for overrides by various criteria -
363             it allows you to specify overridden values for particular generations
364             (if the current generation is greater than or equal to the ones in the
365             config file, with inheritance), for particular physics engines, and
366             for particular hostnames.
367              
368             This is more specific than L can be. This is the
369             interface you should be using in almost all cases.
370              
371             If you don't specify a particular attribute, overrides by that
372             attribute will not show up in the resulting config. This is so you
373             can (for instance) specify a host-specific override for the physics
374             engine, and query that successfully before knowing which physics
375             engine you will be using.
376              
377             Note that you can recurse these, but if you have two paths to the same
378             value, you should not rely on which one takes precedence. In other
379             words, if you have a "byhost" clause within a "bygen" section, and you
380             also have a "bygen" clause within a "byhost" section, either one may
381             eventually be used. When in doubt, simplify your config file.
382              
383             =cut
384              
385             sub custom_config :Export(:DEFAULT) {
386 6     6 1 1161 my %args = @_;
387 6         27 setup_configs();
388             # deep copy
389 6         54 my @configs = Load(Dump(@all_configs));
390              
391 6         326481 my $redo = 1;
392 6         36 while($redo) {
393 8         15 $redo = 0;
394 8         22 foreach my $config (@configs) {
395 28 100       74 if(exists($args{host})) {
396 22         33 my $host = $args{host};
397 22 100 100     89 if(exists($$config{byhost}) && exists($$config{byhost}{$host})) {
398 2         6 push(@configs, $$config{byhost}{$host});
399 2         5 $redo = 1;
400             }
401             }
402 28         73 delete($$config{byhost});
403              
404 28 100       73 if(exists($args{physics})) {
405 22         30 my $physics = $args{physics};
406 22 100 100     78 if(exists($$config{byphysics}) && exists($$config{byphysics}{$physics})) {
407 1         4 push(@configs, $$config{byphysics}{$physics});
408 1         2 $redo = 1;
409             }
410             }
411 28         50 delete($$config{byphysics});
412              
413 28 100       75 if(exists($args{gen})) {
414 22         26 my $mygen = $args{gen};
415 22 100       64 if(exists($$config{bygen})) {
416             # sorted, so that later gens override earlier ones.
417 1         1 foreach my $gen (sort {$a <=> $b} keys %{$$config{bygen}}) {
  5         11  
  1         11  
418 4 100       9 if($mygen >= $gen) {
419 3         9 push(@configs, $$config{bygen}{$gen});
420 3         6 $redo = 1;
421             }
422             }
423             }
424             }
425 28         91 delete($$config{bygen});
426             }
427             }
428              
429             # tally up the values
430 6         20 my %config = ();
431 6         13 foreach my $config (@configs) {
432 18         78 foreach my $keyword (keys %$config) {
433 101         417 $config{$keyword} = $$config{$keyword};
434             }
435             }
436 6         94 return Config->new({ %args, hash => \%config });
437 8     8   6333 }
  8         18  
  8         47  
438              
439             1;