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.