NAME
Text::NumericData::App - tools for applications using Text::NumericData
SYNOPSYS
# usage of the application
my $app = SomeApp->new();
# arguments optional, defaults shown
exit $app->run(\@ARGV, \*STDIN, \*STDOUT);
# The application itself.
package SomeApp;
use Text::NumericData;
use Text::NumericData::App;
our @ISA = ('Text::NumericData::App');
sub new
{
my $class = shift;
# All settings optional.
%setup =
(
parconf=>{info=>'a program that sets the second column to a given value'}
,pardef=>['value',42,'','value to set second column to']
# Optionally bar some parameters of Text::NumericData from command line.
,exclude_pars=>['strict']
);
return $class->SUPER::new(\%setup);
}
sub main
{
my $self = shift;
# Conveniently use common parameter hash.
# Could use something custom, though.
my $txd = Text::NumericData->new($self->{param});
my $data = 0;
while(my $line = <$self->{in}>)
{
unless($data)
{
# Separate header and data.
if($txd->line_check($line)){ $data = 1; }
else{ print {$self->{out}} $line; }
}
if($data)
{
my $d = $txd->line_data($_);
$d->[1] = $self->{param}{value};
print {$self->{out}} ${$txd->data_line($d)};
}
}
return 0;
}
Pipe processing mode
package SomeApp;
use Text::NumericData;
use Text::NumericData::App;
our @ISA = ('Text::NumericData::App');
sub new
{
my $class = shift;
# All settings optional.
%setup =
(
parconf=>{info=>'a program that sets the second column to a given value'}
,pardef=>['value',42,'','value to set second column to']
# Activate pipe mode via Text::ASCIIPipe.
# See documentation about meaning of handler functions.
,pipemode=>1
# Handlers optional, but when you specify none,
# nothing happens.
# $self handle is implicit --- please hand in methods!
,pipe_init => \&init # once before real action
# another option: work on raw line before parsing
# might return true value to skip further processing
#,pipe_preparse => \&check_line
,pipe_begin => \&begin # new file
,pipe_header => \&process_header
,pipe_first_data => \&process_first_data
,pipe_data => \&process_data
# override generic handler that would call the three above
#,pipe_line => \&process_line
,pipe_end => \&end # file end
,pipe_allend => \&allend # total end
);
return $class->SUPER::new(\%setup);
}
# This shall return non-zero on error.
# Other handlers are doomed to be successful.
sub init
{
my $self = shift;
$self->{some_state} = 17;
return 0;
}
sub begin
{
my $self = shift;
# Create fresh Text::NumericData handle.
$self->new_txd(); # This would happen by default, too.
}
sub process_header
{
my $self = shift;
# Do something with $self->{txd} or $_[0] ...
}
sub process_first_data
{
my $s = "# This will be inserted before first data line.\n";
return \$s;
}
sub process_data
{
my $self = shift;
my $d = $txd->line_data($_[0]);
$d->[1] = $self->{param}{value};
$_[0] = ${$txd->data_line($d)};
}
sub end
{
# nothing of interest, could give some report
}
sub allend
{
# see above
}
File-based pipe processing
package SomeApp;
use Text::NumericData;
use Text::NumericData::App;
our @ISA = ('Text::NumericData::App');
sub new
{
my $class = shift;
# All settings optional.
%setup =
(
parconf=>{info=>'a program that sets the second column to a given value'}
,pardef=>['value',42,'','value to set second column to']
# operate on whole file at a time
,filemode=>1
# Note that pipe mode does not add that much functionality,
# the piped reading is built into the Text::NumericData::File class
# already. There's only a basic loop checking special return values.
,pipemode=>1
,pipe_init => \&init
,pipe_file => \&process_file
,pipe_allend => \&allend
);
return $class->SUPER::new(\%setup);
}
# This shall return non-zero on error.
# Other handlers are doomed to be successful.
sub init
{
my $self = shift;
$self->{some_state} = 17;
return 0;
}
# This is supposed to return nozero error if program should abort.
sub process_file
{
my $self = shift;
# Do something with $self->{txd}, which has the current file read in.
return 0; # all fine
}
sub allend
{
# Whatever you see fit to do here.
}
DESCRIPTION
This is wholly intended for building the standard txd* tools, but might be useful for you, too. It glues together Text::NumericData and Config::Param to quickly deploy a command line program that offers a standard parameter set. The setting of pipemode triggers the Text::ASCIIPipe processing pattern.
It merges your parameter definitions with the ones from Text::NumericData, parses command line using Config::Param, and also ensures binary mode for input/output (as Text::NumericData tries to treat line ends explicitly).
Line-based mode
This creates an instance of Text::NumericData as $self->{txd} and is intended to process files line-by-line.
File-based mode
This creates an instance of Text::NumericData::File as $self->{txd} and is intended to read files into $self->{txd} before processing as a whole.
MEMBERS
This base class defines some members that you should know about
- run
-
This is the method that actually runs the program which is fleshed out in a subclass from Text::NumericData::App. It takes 3 optional arguments: ref to command line argument array (defaults to \@ARGV), ref to input (defaults to \*STDIN), ref to output (defaults to \*STDOUT). Those are stored in $self->{argv}, $self->{in} and $self->{out}, respectively.
- param
-
Paramater hash from Config::Param, defining the parameter space for your program including Text::NumericData.
- txd
-
An instance of either Text::NumericData or Text::NumericData::Lines (depending on filemode setting). The default pipemode file-begin handler refreshes this one.
- new_txd
-
The refresh method: Replace $self->{txd} by a new instance. The default pipe_begin callback calls this to give you something to work with. It's also called before running main() when not in pipemode.
- argv, in, out
-
The places where run method stores the currently active argument array and input/output handles.
- setup
-
Well, actually, you defined that: This is the configuration hash handed to the constructor, extended a bit by this (additional setup of Config::Param, for example).
- state
-
A general-purpose hash with some state information. Of interest might be $self->{state}{data}, which indicates if we hit the data section of the file. But if you need to handle that explicitly, you'll manage your own state.
- default_line_hook
-
Method that runs when you do not override pipe_line.
- error
-
Simple wrapper to print out a message and return a given value or -1 per default. This is to cut down such code in main or init methods:
if($some_bad_thing) { print STDERR "Some error occured!\n"; return $bad_return_value; }
to
return $self->error("Some error occured", $bad_return_value) if $some_bad_thing;
So it doesn't do much yet. It might carry an error count and do something with it.