Wednesday, October 14, 2009

Statistic Calculator: Final Console Application

[Spanish original]
In the last article we left pending to make our interpreter to recognize  parameters and be able to print any return value from the Statistics::Descriptive functions.
First we should define how to delimit commands and parameters, the easiest way to do it is like the unix shell does, using whitespace to delimit both, so once you get a line of commands:
34     $command =~ s/^\s+//; $command =~ s/\s+$//;
35     my @args = split /\s+/, $command;
36     my $oper = looks_like_number( $args[0] ) ? "add_data" : shift @args;
spaces are removed at the beginning and end (34), split all the elements separated by one or more white (35), and get the operation to perform (36) which is usually the first element, except when a number is read, in which case the implicit operation is "add_date". After these operations the operation to be performed is in $oper and its arguments are in @args, so it only remains to apply the operation:

38         when (%FUNCS)               { apply( $oper, @args ) }
The routine in charge of the implementation of the operation must get the arguments (26), assess the operation in context list (27), why should be that in list context?, to allow operations like "percentile" return multiple values.
La rutina a cargo de la aplicación de la operación debe obtener los argumentos (26), evaluar la operación en contexto lista (27), ¿por qué en contexto lista?, para permitir operaciones como "percentile" que produce múltiples valores.

Once the value is calculated, we had to check whether it is worth printing, so we simply return if @result is empty (28), or if you have a single element but is not defined or empty string (29).
To print complex values I will use the YAML format, because it is very readable and perl has a very good YAML module available from CPAN.
So depending on the number of elements in @result will print the first element or or the entire array converted to YAML text (30).
The calculator then console looks like:
 1 #!/usr/bin/perl
 2 
 3 use Modern::Perl;
 4 use Scalar::Util qw( looks_like_number );
 5 use Statistics::Descriptive;
 6 use Pod::Perldoc;
 7 use Term::ReadLine;
 8 use YAML;
 9 
10 my $term = new Term::ReadLine 'Statistic Calculator';
11 
12 my %FUNCS = map { $_ => 1 } qw( sum mean count variance standard_deviation
13     min mindex max maxdex sample_range median harmonic_mean geometric_mean
14     mode trimmed_mean clear add_data percentile quantile least_squares_fit
15     frequency_distribution_ref frequency_distribution);
16 
17 my @COMMANDS = qw( exit quit help man );
18 
19 sub help { say "Comandos: " . join( ", ", sort @COMMANDS, keys %FUNCS ) }
20 
21 sub man { Pod::Perldoc->new( args => \@_ )->process }
22 
23 my $s = Statistics::Descriptive::Full->new();
24 
25 sub apply {
26     my ( $oper, @args ) = @_;
27     my @result = $s->$oper(@args);
28     return unless @result;
29     return unless @result > 1 or (defined $result[0] and $result[0] ne "");
30     say YAML::Dump( @result == 1 ? $result[0] : \@result );
31 }
32 
33 while ( defined( my $command = $term->readline("Listo> ") ) ) {
34     $command =~ s/^\s+//; $command =~ s/\s+$//;
35     my @args = split( /\s+/, $command ) or next;
36     my $oper = looks_like_number( $args[0] ) ? "add_data" : shift @args;
37     given ($oper) {
38         when (%FUNCS)               { apply( $oper, @args ) }
39         when ("man")                { man "Statistics::Descriptive" }
40         when ( [ "exit", "quit" ] ) {last}
41         when ("help")               {help}
42         default                     { say "Error: tipee 'help' para ayuda" };
43     }
44 }
After this series of articles, I hope you can appreciate how fast you can work in Perl, using the mechanisms offered by the language and the vast amount of tools available on the CPAN.
In future articles will use this example to illustrate other techniques such as web programming, object-oriented Perl and of course more modules from CPAN.

No comments:

Post a Comment